From c0f363037dc0a3ea8c00ee9817dce4d206631d2c Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 26 Sep 2018 19:52:42 +0100 Subject: [PATCH 01/63] Add `getDefaultExcluded` --- contracts/modules/Checkpoint/DividendCheckpoint.sol | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index e427509ab..67948ca02 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -61,6 +61,14 @@ contract DividendCheckpoint is ICheckpoint, Module { return bytes4(0); } + /** + * @notice Return the default excluded addresses + * @return List of excluded addresses + */ + function getDefaultExcluded() external view returns (address[]) { + return excluded; + } + /** * @notice Function to set withholding tax rates for investors * @param _investors addresses of investor @@ -157,7 +165,7 @@ contract DividendCheckpoint is ICheckpoint, Module { * @notice Calculate amount of dividends claimable * @param _dividendIndex Dividend to calculate * @param _payee Affected investor address - * @return unit256 + * @return claim, withheld amounts */ function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { require(_dividendIndex < dividends.length, "Incorrect dividend index"); From 45550bbb2a82906bd8cb433f4acf628ba3c5fcd4 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Wed, 26 Sep 2018 22:05:20 +0100 Subject: [PATCH 02/63] Add events for withholding tax and change to setDefaultExcluded --- .../modules/Checkpoint/DividendCheckpoint.sol | 30 +++++++++++-------- test/e_erc20_dividends.js | 4 +-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index 67948ca02..d751e02fe 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -43,7 +43,9 @@ contract DividendCheckpoint is ICheckpoint, Module { // Total amount of ETH withheld per investor mapping (address => uint256) public investorWithheld; - event SetExcludedAddresses(address[] _excluded, uint256 _timestamp); + event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); + event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); + event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); modifier validDividendIndex(uint256 _dividendIndex) { require(_dividendIndex < dividends.length, "Incorrect dividend index"); @@ -69,6 +71,16 @@ contract DividendCheckpoint is ICheckpoint, Module { return excluded; } + /** + * @notice Function to clear and set list of excluded addresses used for future dividends + * @param _excluded addresses of investor + */ + function setDefaultExcluded(address[] _excluded) public onlyOwner { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); + excluded = _excluded; + emit SetDefaultExcludedAddresses(excluded, now); + } + /** * @notice Function to set withholding tax rates for investors * @param _investors addresses of investor @@ -76,29 +88,21 @@ contract DividendCheckpoint is ICheckpoint, Module { */ function setWithholding(address[] _investors, uint256[] _withholding) public onlyOwner { require(_investors.length == _withholding.length, "Mismatched input lengths"); + emit SetWithholding(_investors, _withholding, now); for (uint256 i = 0; i < _investors.length; i++) { - require(_withholding[i] <= 10**18); + require(_withholding[i] <= 10**18, "Incorrect withholding tax"); withholdingTax[_investors[i]] = _withholding[i]; } } - /** - * @notice Function to clear and set list of excluded addresses used for future dividends - * @param _excluded addresses of investor - */ - function setExcluded(address[] _excluded) public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); - excluded = _excluded; - emit SetExcludedAddresses(excluded, now); - } - /** * @notice Function to set withholding tax rates for investors * @param _investors addresses of investor * @param _withholding withholding tax for all investors (multiplied by 10**16) */ function setWithholdingFixed(address[] _investors, uint256 _withholding) public onlyOwner { - require(_withholding <= 10**18); + require(_withholding <= 10**18, "Incorrect withholding tax"); + emit SetWithholdingFixed(_investors, _withholding, now); for (uint256 i = 0; i < _investors.length; i++) { withholdingTax[_investors[i]] = _withholding; } diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 4e4812419..52570446a 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -583,7 +583,7 @@ contract('ERC20DividendCheckpoint', accounts => { }); it("Exclude account_temp using global exclusion list", async() => { - await I_ERC20DividendCheckpoint.setExcluded([account_temp], {from: token_owner}); + await I_ERC20DividendCheckpoint.setDefaultExcluded([account_temp], {from: token_owner}); }); it("Create another new dividend", async() => { @@ -657,7 +657,7 @@ contract('ERC20DividendCheckpoint', accounts => { it("Delete global exclusion list", async() => { - await I_ERC20DividendCheckpoint.setExcluded([], {from: token_owner}); + await I_ERC20DividendCheckpoint.setDefaultExcluded([], {from: token_owner}); }); From 8a0d25b51dd86a1aa461ceddb90d00783174b34e Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 26 Sep 2018 09:41:32 -0300 Subject: [PATCH 03/63] CLI: Switch over text menu options instead of indexes. --- CLI/commands/dividends_manager.js | 35 ++++++++++++------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index 0c147545c..a84a15067 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -109,54 +109,46 @@ async function start_explorer(){ } let index = readlineSync.keyInSelect(options, 'What do you want to do?'); - console.log('Selected:', index != -1 ? options[index] : 'Cancel', '\n'); - switch (index) { - case 0: - // Mint tokens + let selected = index != -1 ? options[index] : 'Cancel'; + console.log('Selected:', selected, '\n'); + switch (selected) { + case 'Mint tokens': let _to = readlineSync.question('Enter beneficiary of minting: '); let _amount = readlineSync.question('Enter amount of tokens to mint: '); await mintTokens(_to,_amount); break; - case 1: - // Transfer tokens + case 'Transfer tokens': let _to2 = readlineSync.question('Enter beneficiary of tranfer: '); let _amount2 = readlineSync.question('Enter amount of tokens to transfer: '); await transferTokens(_to2,_amount2); break; - case 2: - // Create checkpoint + case 'Create checkpoint': let createCheckpointAction = securityToken.methods.createCheckpoint(); await common.sendTransaction(Issuer, createCheckpointAction, defaultGasPrice); break; - case 3: - // Create Dividends + case 'Create dividends': let dividend = readlineSync.question(`How much ${dividendsType} would you like to distribute to token holders?: `); await checkBalance(dividend); let checkpointId = currentCheckpoint == 0 ? 0 : await selectCheckpoint(true); // If there are no checkpoints, it must create a new one await createDividends(dividend, checkpointId); break; - case 4: - // Explore account at checkpoint + case 'Explore account at checkpoint': let _address = readlineSync.question('Enter address to explore: '); let _checkpoint = await selectCheckpoint(false); await exploreAddress(_address, _checkpoint); break; - case 5: - // Explore total supply at checkpoint + case 'Explore total supply at checkpoint': let _checkpoint2 = await selectCheckpoint(false); await exploreTotalSupply(_checkpoint2); break; - break; - case 6: - // Push dividends to account + case 'Push dividends to accounts': let _dividend = await selectDividend({valid: true, expired: false, reclaimed: false}); if (_dividend !== null) { let _addresses = readlineSync.question('Enter addresses to push dividends to (ex- add1,add2,add3,...): '); await pushDividends(_dividend, _addresses); } break; - case 7: - //explore balance + case `Explore ${dividendsType} balance`: let _address3 = readlineSync.question('Enter address to explore: '); let _dividend3 = await selectDividend(); if (_dividend3 !== null) { @@ -168,14 +160,13 @@ async function start_explorer(){ `); } break; - case 8: - // Reclaimed dividends after expiry + case 'Reclaim expired dividends': let _dividend4 = await selectDividend({expired: true, reclaimed: false}); if (_dividend4 !== null) { await reclaimedDividend(_dividend4); } break; - case -1: + case 'Cancel': process.exit(0); break; } From 6120339d13f51ee51df0fa1da0fcec168c6553d1 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Thu, 27 Sep 2018 10:19:58 -0300 Subject: [PATCH 04/63] CLI: Support for tax withholding and exclusions from dividends. --- CLI/commands/dividends_manager.js | 141 +++++++++++++++++++++++--- CLI/data/dividendsExclusions_data.csv | 6 ++ 2 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 CLI/data/dividendsExclusions_data.csv diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index a84a15067..609338839 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -96,7 +96,7 @@ async function start_explorer(){ let currentCheckpoint = await securityToken.methods.currentCheckpointId().call(); console.log(chalk.yellow(`\nToken is at checkpoint: ${currentCheckpoint}`)); - let options = ['Mint tokens', 'Transfer tokens', 'Create checkpoint', 'Create dividends'] + let options = ['Mint tokens', 'Transfer tokens', 'Create checkpoint', 'Set default exclusions for dividends', 'Tax holding settings', 'Create dividends'] if (currentCheckpoint > 0) { options.push('Explore account at checkpoint', 'Explore total supply at checkpoint') @@ -126,6 +126,12 @@ async function start_explorer(){ let createCheckpointAction = securityToken.methods.createCheckpoint(); await common.sendTransaction(Issuer, createCheckpointAction, defaultGasPrice); break; + case 'Set default exclusions for dividends': + await setDefaultExclusions(); + break; + case 'Tax holding settings': + await taxHoldingMenu(); + break; case 'Create dividends': let dividend = readlineSync.question(`How much ${dividendsType} would you like to distribute to token holders?: `); await checkBalance(dividend); @@ -142,7 +148,7 @@ async function start_explorer(){ await exploreTotalSupply(_checkpoint2); break; case 'Push dividends to accounts': - let _dividend = await selectDividend({valid: true, expired: false, reclaimed: false}); + let _dividend = await selectDividend({valid: true, expired: false, reclaimed: false, withRemaining: true}); if (_dividend !== null) { let _addresses = readlineSync.question('Enter addresses to push dividends to (ex- add1,add2,add3,...): '); await pushDividends(_dividend, _addresses); @@ -240,6 +246,69 @@ async function exploreTotalSupply(checkpoint){ console.log(`TotalSupply is: ${totalSupplyAt} (Using totalSupplyAt - checkpoint ${checkpoint})`); } +async function setDefaultExclusions() { + await addDividendsModule(); + + let excluded = await currentDividendsModule.methods.getDefaultExcluded().call(); + showExcluded(excluded); + + console.log(chalk.yellow(`Excluded addresses will be loaded from 'dividendsExclusions_data.csv'. Please check your data before continue.`)); + if (readlineSync.keyInYNStrict(`Do you want to continue?`)) { + let excluded = getExcludedFromDataFile(); + let setDefaultExclusionsActions = currentDividendsModule.methods.setDefaultExcluded(excluded); + let receipt = await common.sendTransaction(Issuer, setDefaultExclusionsActions, defaultGasPrice); + let event = common.getEventFromLogs(currentDividendsModule._jsonInterface, receipt.logs, 'SetDefaultExcludedAddresses'); + console.log(chalk.green(`Exclusions were successfuly set.`)); + showExcluded(event._excluded); + } +} + +async function taxHoldingMenu() { + await addDividendsModule(); + + let options = ['Set a % to withhold from dividends sent to an address', 'Withdraw withholding for dividend', 'Return to main menu']; + let index = readlineSync.keyInSelect(options, 'What do you want to do?', {cancel: false}); + let selected = options[index]; + console.log("Selected:", selected); + switch (selected) { + case 'Set a % to withhold from dividends sent to an address': + let address = readlineSync.question('Enter the address of the investor: ', { + limit: function(input) { + return web3.utils.isAddress(input); + }, + limitMessage: "Must be a valid address", + }); + let percentage = readlineSync.question('Enter the percentage of dividends to withhold (number between 0-100): ', { + limit: function(input) { + return (parseInt(input) >= 0 && parseInt(input) <= 100); + }, + limitMessage: "Must be a value between 0 and 100", + }); + let percentageWei = web3.utils.toWei((percentage / 100).toString()); + let setWithHoldingFixedAction = currentDividendsModule.methods.setWithholdingFixed([address], percentageWei); + let receipt = await common.sendTransaction(Issuer, setWithHoldingFixedAction, defaultGasPrice); + console.log(chalk.green(`Successfully set tax withholding of ${percentage}% for ${address}.`)); + break; + case 'Withdraw withholding for dividend': + let _dividend = await selectDividend({withRemainingWithheld: true}); + if (_dividend !== null) { + let withdrawWithholdingAction = currentDividendsModule.methods.withdrawWithholding(_dividend.index); + let receipt = await common.sendTransaction(Issuer, withdrawWithholdingAction, defaultGasPrice); + let eventName; + if (dividendsType == 'POLY') { + eventName = 'ERC20DividendWithholdingWithdrawn'; + } else if (dividendsType == 'ETH') { + eventName = 'EtherDividendWithholdingWithdrawn'; + } + let event = common.getEventFromLogs(currentDividendsModule._jsonInterface, receipt.logs, eventName); + console.log(chalk.green(`Successfully withdrew ${web3.utils.fromWei(event._withheldAmount)} ${dividendsType} from dividend ${_dividend.index} tax withholding.`)); + } + break; + case 'Return to main menu': + break; + } +} + async function createDividends(dividend, checkpointId) { await addDividendsModule(); @@ -247,26 +316,46 @@ async function createDividends(dividend, checkpointId) { let maturityTime = readlineSync.questionInt('Enter the dividend maturity time from which dividend can be paid (Unix Epoch time)\n(Now = ' + time + ' ): ', {defaultInput: time}); let defaultTime = time + duration.minutes(10); let expiryTime = readlineSync.questionInt('Enter the dividend expiry time (Unix Epoch time)\n(10 minutes from now = ' + defaultTime + ' ): ', {defaultInput: defaultTime}); + + let useDefaultExcluded = readlineSync.keyInYNStrict(`Do you want to use the default excluded addresses for this dividend? If not, data from 'dividendsExclusions_data.csv' will be used instead.`); let createDividendAction; if (dividendsType == 'POLY') { let approveAction = polyToken.methods.approve(currentDividendsModule._address, web3.utils.toWei(dividend)); await common.sendTransaction(Issuer, approveAction, defaultGasPrice); if (checkpointId > 0) { - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId); + if (useDefaultExcluded) { + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId); + } else { + let excluded = getExcludedFromDataFile(); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, excluded); + } } else { - createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend)); + if (useDefaultExcluded) { + createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend)); + } else { + let excluded = getExcludedFromDataFile(); + createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), excluded); + } } let receipt = await common.sendTransaction(Issuer, createDividendAction, defaultGasPrice); let event = common.getEventFromLogs(currentDividendsModule._jsonInterface, receipt.logs, 'ERC20DividendDeposited'); - console.log(` - Dividend ${event._dividendIndex} deposited` - ); + console.log(chalk.green(`Dividend ${event._dividendIndex} deposited`)); } else if (dividendsType == 'ETH') { if (checkpointId > 0) { - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, checkpointId); + if (useDefaultExcluded) { + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, checkpointId); + } else { + let excluded = getExcludedFromDataFile(); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, checkpointId, excluded); + } } else { - createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime); + if (useDefaultExcluded) { + createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime); + } else { + let excluded = getExcludedFromDataFile(); + createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, excluded); + } } let receipt = await common.sendTransaction(Issuer, createDividendAction, defaultGasPrice, web3.utils.toWei(dividend)); let event = common.getEventFromLogs(currentDividendsModule._jsonInterface, receipt.logs, 'EtherDividendDeposited'); @@ -299,7 +388,8 @@ async function pushDividends(dividend, account){ for (const event of successEvents) { console.log(` Claimed ${web3.utils.fromWei(event._amount)} ${dividendsType} - to account ${event._payee}` + to account ${event._payee} + ${web3.utils.fromWei(event._withheld)} ${dividendsType} of tax withheld` ); } } @@ -441,6 +531,12 @@ async function selectDividend(filter) { if (typeof filter.reclaimed !== 'undefined') { dividends = dividends.filter(d => filter.reclaimed == d.reclaimed); } + if (typeof filter.withRemainingWithheld !== 'undefined') { + dividends = dividends.filter(d => new web3.utils.BN(d.dividendWithheld).sub(new web3.utils.BN(d.dividendWithheldReclaimed)) > 0); + } + if (typeof filter.withRemaining !== 'undefined') { + dividends = dividends.filter(d => new web3.utils.BN(d.amount).sub(new web3.utils.BN(d.claimedAmount)) > 0); + } } if (dividends.length > 0) { @@ -448,9 +544,11 @@ async function selectDividend(filter) { return `Created: ${moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')} Maturity: ${moment.unix(d.maturity).format('MMMM Do YYYY, HH:mm:ss')} Expiry: ${moment.unix(d.expiry).format('MMMM Do YYYY, HH:mm:ss')} + At checkpoint: ${d.checkpointId} Amount: ${web3.utils.fromWei(d.amount)} ${dividendsType} Claimed Amount: ${web3.utils.fromWei(d.claimedAmount)} ${dividendsType} - At checkpoint: ${d.checkpointId}` + Withheld: ${web3.utils.fromWei(d.dividendWithheld)} ${dividendsType} + Withheld claimed: ${web3.utils.fromWei(d.dividendWithheldReclaimed)} ${dividendsType}` }); let index = readlineSync.keyInSelect(options, 'Select a dividend:'); @@ -459,7 +557,8 @@ async function selectDividend(filter) { } } else { console.log(chalk.red(`No dividends were found meeting the requirements`)) - console.log(chalk.red(`Requirements: Valid: ${filter.valid} - Expired: ${filter.expired} - Reclaimed: ${filter.reclaimed}\n`)) + console.log(chalk.red(`Requirements: Valid: ${filter.valid} - Expired: ${filter.expired} - Reclaimed: ${filter.reclaimed} + WithRemainingWithheld: ${filter.withRemainingWithheld} - WithRemaining: ${filter.withRemaining}\n`)) } return result; @@ -481,6 +580,24 @@ async function getDividends() { return result; } +function getExcludedFromDataFile() { + let excludedFromFile = require('fs').readFileSync('./CLI/data/dividendsExclusions_data.csv').toString().split("\n"); + let excluded = excludedFromFile.filter(function (address) { + return web3.utils.isAddress(address); + }); + return excluded; +} + +function showExcluded(excluded) { + if (excluded.length > 0) { + console.log('Current default excluded addresses:') + excluded.map(function (address) { console.log(' ', address) }); + } else { + console.log('There are not default excluded addresses.') + } + console.log(); +} + module.exports = { executeApp: async function(type, remoteNetwork) { return executeApp(type, remoteNetwork); diff --git a/CLI/data/dividendsExclusions_data.csv b/CLI/data/dividendsExclusions_data.csv new file mode 100644 index 000000000..b418985eb --- /dev/null +++ b/CLI/data/dividendsExclusions_data.csv @@ -0,0 +1,6 @@ +0xa26cc0567e29fda3c77369791e926b4c46456fcb +0x97c09f763a699a51cb947f95e602c08f7bcba202 +0x308a3ea530e5b160f1f7115f2ddb30cb44d8b54d +0xbc1bfb5d90692854672febe76ca5379dea1015e4 +0x7442dcd2eb074ea6dbfaa8338300bc86238c2aae +0x0a519b4b6501f92e8f516230b97aca83257b0c01 \ No newline at end of file From 9e9b0e3255db7930f536ddce4e1b2eda61367f04 Mon Sep 17 00:00:00 2001 From: satyam Date: Thu, 27 Sep 2018 20:24:30 +0530 Subject: [PATCH 05/63] overruling the whenNotPaused modifier when msg.sender is owner --- contracts/ModuleRegistry.sol | 10 +++++++--- contracts/SecurityTokenRegistry.sol | 11 ++++++++--- test/k_module_registry.js | 2 +- test/n_security_token_registry.js | 12 ------------ 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index 94878303d..b9c72c0dd 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -70,8 +70,12 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { - require(!getBool(Encoder.getKey("paused")), "Already paused"); - _; + if (msg.sender == getAddress(Encoder.getKey("owner"))) + _; + else { + require(!getBool(Encoder.getKey("paused")), "Already paused"); + _; + } } /** @@ -296,7 +300,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { /** * @notice Called by the owner to pause, triggers stopped state */ - function pause() external whenNotPaused onlyOwner { + function pause() external onlyOwner { set(Encoder.getKey("paused"), true); emit Pause(now); } diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 9a4e66b0b..495d7c3df 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -116,10 +116,15 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { - require(!getBool(Encoder.getKey("paused")), "Already paused"); - _; + if (msg.sender == getAddress(Encoder.getKey("owner"))) + _; + else { + require(!getBool(Encoder.getKey("paused")), "Already paused"); + _; + } } + /** * @notice Modifier to make a function callable only when the contract is paused. */ @@ -557,7 +562,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { /** * @notice called by the owner to pause, triggers stopped state */ - function pause() external whenNotPaused onlyOwner { + function pause() external onlyOwner { set(Encoder.getKey("paused"), true); emit Pause(now); } diff --git a/test/k_module_registry.js b/test/k_module_registry.js index 6843db491..55cd836e0 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -261,7 +261,7 @@ contract('ModuleRegistry', accounts => { await I_MRProxied.pause({from: account_polymath}); let errorThrown = false; try { - let tx = await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, {from: account_polymath}); + let tx = await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, {from: account_delegate}); } catch(error) { console.log(` tx -> revert because already registered modules are not allowed`); errorThrown = true; diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index a53378c8b..3ccb90f8b 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -383,18 +383,6 @@ contract('SecurityTokenRegistry', accounts => { assert.ok(errorThrown, message); }); - it("Should fail to pause if already paused", async() => { - let errorThrown = false; - try { - await I_STRProxied.pause({ from: account_polymath}); - } catch(error) { - console.log(` tx revert -> Registration is already paused`.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - }); - it("Should successfully register ticker if registration is unpaused", async() => { await I_STRProxied.unpause({ from: account_polymath}); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); From 1ebe0da1d7957ccf98e4650fc3bb2cce5d8b077c Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Thu, 27 Sep 2018 15:25:55 -0300 Subject: [PATCH 06/63] Start ethereum bridge only on Travis CI cron jobs --- scripts/test.sh | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index 1ab73ed74..28619d3af 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -72,19 +72,25 @@ start_testrpc() { if testrpc_running; then echo "Using existing testrpc instance" - bridge_running - if bridge_running; then - echo "Using existing ethereum-bridge instance" - else - echo "Runnning the new ethereum-bridge instance" - start_bridge + # Do not start ethereum bridge unless it is a cron job from travis + if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then + bridge_running + if bridge_running; then + echo "Using existing ethereum-bridge instance" + else + echo "Runnning the new ethereum-bridge instance" + start_bridge + fi fi else echo "Starting our own testrpc instance" start_testrpc - echo "Starting our own ethereum-bridge instance" - sleep 10 - start_bridge + # Do not start ethereum bridge unless it is a cron job from travis + if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then + echo "Starting our own ethereum-bridge instance" + sleep 10 + start_bridge + fi fi if ! [ -z "${TRAVIS_PULL_REQUEST+x}" ] && [ "$TRAVIS_PULL_REQUEST" != false ]; then @@ -94,5 +100,10 @@ if ! [ -z "${TRAVIS_PULL_REQUEST+x}" ] && [ "$TRAVIS_PULL_REQUEST" != false ]; t cat coverage/lcov.info | node_modules/.bin/coveralls fi else - node_modules/.bin/truffle test `ls test/*.js` + # Do not run a_poly_oracle,js tests unless it is a cron job from travis + if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then + node_modules/.bin/truffle test `ls test/*.js` + else + node_modules/.bin/truffle test `find test/*.js ! -name a_poly_oracle.js` + fi fi From f09c2f6267eb49f84a9da5c1dc50436d579161be Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Thu, 27 Sep 2018 15:51:21 -0300 Subject: [PATCH 07/63] Exclude s_v130_to_v140_upgrade.js test --- scripts/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test.sh b/scripts/test.sh index 28619d3af..d6fb7a632 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -104,6 +104,6 @@ else if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then node_modules/.bin/truffle test `ls test/*.js` else - node_modules/.bin/truffle test `find test/*.js ! -name a_poly_oracle.js` + node_modules/.bin/truffle test `find test/*.js ! -name a_poly_oracle.js -and ! -name s_v130_to_v140_upgrade.js` fi fi From e70b072ef9ee295d8d4e9eb6068e548f69fa637d Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Thu, 27 Sep 2018 22:33:27 +0100 Subject: [PATCH 08/63] Update burn functions --- contracts/interfaces/ISecurityToken.sol | 23 +++-- contracts/tokens/SecurityToken.sol | 109 ++++++++++++++---------- 2 files changed, 77 insertions(+), 55 deletions(-) diff --git a/contracts/interfaces/ISecurityToken.sol b/contracts/interfaces/ISecurityToken.sol index 33e38201c..c36f45270 100644 --- a/contracts/interfaces/ISecurityToken.sol +++ b/contracts/interfaces/ISecurityToken.sol @@ -19,15 +19,15 @@ interface ISecurityToken { event Approval(address indexed owner, address indexed spender, uint256 value); //transfer, transferFrom must respect use respect the result of verifyTransfer - function verifyTransfer(address _from, address _to, uint256 _amount) external returns (bool success); + function verifyTransfer(address _from, address _to, uint256 _value) external returns (bool success); /** * @notice mints new tokens and assigns them to the target _investor. * Can only be called by the STO attached to the token (Or by the ST owner if there's no STO attached yet) * @param _investor address the tokens will be minted to - * @param _amount is the amount of tokens that will be minted to the investor + * @param _value is the amount of tokens that will be minted to the investor */ - function mint(address _investor, uint256 _amount) external returns (bool success); + function mint(address _investor, uint256 _value) external returns (bool success); /** * @notice Burn function used to burn the securityToken @@ -35,7 +35,14 @@ interface ISecurityToken { */ function burn(uint256 _value) external returns (bool success); - event Minted(address indexed to, uint256 amount); + /** + * @notice Burn function used to burn the securityToken on behalf of someone else + * @param _from Address for whom to burn tokens + * @param _value No. of token that get burned + */ + function burnFrom(address _from, uint256 _value) external returns (bool success); + + event Minted(address indexed _to, uint256 _value); event Burnt(address indexed _burner, uint256 _value); // Permissions this to a Permission module, which has a key of 1 @@ -118,9 +125,9 @@ interface ISecurityToken { /** * @notice allows the owner to withdraw unspent POLY stored by them on the ST. * @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee. - * @param _amount amount of POLY to withdraw + * @param _value amount of POLY to withdraw */ - function withdrawPoly(uint256 _amount) external; + function withdrawPoly(uint256 _value) external; /** * @notice allows owner to approve more POLY to one of the modules @@ -168,10 +175,10 @@ interface ISecurityToken { * @notice mints new tokens and assigns them to the target investors. * Can only be called by the STO attached to the token or by the Issuer (Security Token contract owner) * @param _investors A list of addresses to whom the minted tokens will be delivered - * @param _amounts A list of the amount of tokens to mint to corresponding addresses from _investor[] list + * @param _values A list of the amount of tokens to mint to corresponding addresses from _investor[] list * @return success */ - function mintMulti(address[] _investors, uint256[] _amounts) external returns (bool success); + function mintMulti(address[] _investors, uint256[] _values) external returns (bool success); /** * @notice used to set the token Burner address. It can only be called by the owner diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index f8d91c389..0b85e6762 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -132,12 +132,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Change the STR address in the event of a upgrade event ChangeSTRAddress(address indexed _oldAddress, address indexed _newAddress); // Events to log minting and burning - event Minted(address indexed to, uint256 amount); + event Minted(address indexed _to, uint256 _value); event Burnt(address indexed _burner, uint256 _value); // Events to log controller actions event SetController(address indexed _oldController, address indexed _newController); - event ForceTransfer(address indexed _controller, address indexed _from, address indexed _to, uint256 _amount, bool _verifyTransfer, bytes _data); + event ForceTransfer(address indexed _controller, address indexed _from, address indexed _to, uint256 _value, bool _verifyTransfer, bytes _data); event DisableController(uint256 _timestamp); function isModule(address _module, uint8 _type) internal view returns (bool) { @@ -163,8 +163,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } } - modifier checkGranularity(uint256 _amount) { - require(_amount % granularity == 0, "Unable to modify token balances at this granularity"); + modifier checkGranularity(uint256 _value) { + require(_value % granularity == 0, "Unable to modify token balances at this granularity"); _; } @@ -360,10 +360,10 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr /** * @notice allows the owner to withdraw unspent POLY stored by them on the ST. * @dev Owner can transfer POLY to the ST which will be used to pay for modules that require a POLY fee. - * @param _amount amount of POLY to withdraw + * @param _value amount of POLY to withdraw */ - function withdrawPoly(uint256 _amount) external onlyOwner { - require(ERC20(polyToken).transfer(owner, _amount), "In-sufficient balance"); + function withdrawPoly(uint256 _value) external onlyOwner { + require(ERC20(polyToken).transfer(owner, _value), "In-sufficient balance"); } /** @@ -540,13 +540,17 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value value of transfer * @return bool success */ - function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { + function transferFrom(address _from, address _to, uint256 _value) public returns(bool) { + require(_updateTransfer(_from, _to, _value), "Transfer is not valid"); + require(super.transferFrom(_from, _to, _value)); + return true; + } + + function _updateTransfer(address _from, address _to, uint256 _value) internal returns(bool) { _adjustInvestorCount(_from, _to, _value); - require(_verifyTransfer(_from, _to, _value, true), "Transfer is not valid"); _adjustBalanceCheckpoints(_from); _adjustBalanceCheckpoints(_to); - require(super.transferFrom(_from, _to, _value)); - return true; + return _verifyTransfer(_from, _to, _value, true); } /** @@ -554,11 +558,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @dev TransferManager module has a key of 2 * @param _from sender of transfer * @param _to receiver of transfer - * @param _amount value of transfer + * @param _value value of transfer * @param _isTransfer whether transfer is being executed * @return bool */ - function _verifyTransfer(address _from, address _to, uint256 _amount, bool _isTransfer) internal checkGranularity(_amount) returns (bool) { + function _verifyTransfer(address _from, address _to, uint256 _value, bool _isTransfer) internal checkGranularity(_value) returns (bool) { if (!transfersFrozen) { if (modules[TRANSFERMANAGER_KEY].length == 0) { return true; @@ -572,7 +576,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr module = modules[TRANSFERMANAGER_KEY][i]; if (!modulesToData[module].isArchived) { unarchived = true; - ITransferManager.Result valid = ITransferManager(module).verifyTransfer(_from, _to, _amount, _isTransfer); + ITransferManager.Result valid = ITransferManager(module).verifyTransfer(_from, _to, _value, _isTransfer); if (valid == ITransferManager.Result.INVALID) { isInvalid = true; } @@ -595,11 +599,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @dev TransferManager module has a key of 2 * @param _from sender of transfer * @param _to receiver of transfer - * @param _amount value of transfer + * @param _value value of transfer * @return bool */ - function verifyTransfer(address _from, address _to, uint256 _amount) public returns (bool) { - return _verifyTransfer(_from, _to, _amount, false); + function verifyTransfer(address _from, address _to, uint256 _value) public returns (bool) { + return _verifyTransfer(_from, _to, _value, false); } /** @@ -615,19 +619,19 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice mints new tokens and assigns them to the target _investor. * @dev Can only be called by the issuer or STO attached to the token * @param _investor Address where the minted tokens will be delivered - * @param _amount Number of tokens be minted + * @param _value Number of tokens be minted * @return success */ - function mint(address _investor, uint256 _amount) public onlyModuleOrOwner(STO_KEY) checkGranularity(_amount) isMintingAllowed() returns (bool success) { + function mint(address _investor, uint256 _value) public onlyModuleOrOwner(STO_KEY) checkGranularity(_value) isMintingAllowed() returns (bool success) { require(_investor != address(0), "Investor address should not be 0x"); - _adjustInvestorCount(address(0), _investor, _amount); - require(_verifyTransfer(address(0), _investor, _amount, true), "Transfer is not valid"); + _adjustInvestorCount(address(0), _investor, _value); + require(_verifyTransfer(address(0), _investor, _value, true), "Transfer is not valid"); _adjustBalanceCheckpoints(_investor); _adjustTotalSupplyCheckpoints(); - totalSupply_ = totalSupply_.add(_amount); - balances[_investor] = balances[_investor].add(_amount); - emit Minted(_investor, _amount); - emit Transfer(address(0), _investor, _amount); + totalSupply_ = totalSupply_.add(_value); + balances[_investor] = balances[_investor].add(_value); + emit Minted(_investor, _value); + emit Transfer(address(0), _investor, _value); return true; } @@ -635,13 +639,13 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice mints new tokens and assigns them to the target _investor. * @dev Can only be called by the issuer or STO attached to the token. * @param _investors A list of addresses to whom the minted tokens will be dilivered - * @param _amounts A list of number of tokens get minted and transfer to corresponding address of the investor from _investor[] list + * @param _values A list of number of tokens get minted and transfer to corresponding address of the investor from _investor[] list * @return success */ - function mintMulti(address[] _investors, uint256[] _amounts) external onlyModuleOrOwner(STO_KEY) returns (bool success) { - require(_investors.length == _amounts.length, "Mis-match in the length of the arrays"); + function mintMulti(address[] _investors, uint256[] _values) external onlyModuleOrOwner(STO_KEY) returns (bool success) { + require(_investors.length == _values.length, "Mis-match in the length of the arrays"); for (uint256 i = 0; i < _investors.length; i++) { - mint(_investors[i], _amounts[i]); + mint(_investors[i], _values[i]); } return true; } @@ -675,25 +679,40 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr tokenBurner = ITokenBurner(_tokenBurner); } + function _burn(address _from, uint256 _value) internal returns (bool) { + require(tokenBurner != address(0), "Token Burner contract address is not set yet"); + require(_value <= balances[_from], "Value too high"); + _updateTransfer(_from, address(0), _value); + + // no need to require value <= totalSupply, since that would imply the + // sender's balance is greater than the totalSupply, which *should* be an assertion failure + balances[_from] = balances[_from].sub(_value); + totalSupply_ = totalSupply_.sub(_value); + require(tokenBurner.burn(_from, _value), "Token burner failed"); + emit Burnt(_from, _value); + emit Transfer(_from, address(0), _value); + return true; + } + /** * @notice Burn function used to burn the securityToken * @param _value No. of token that get burned */ function burn(uint256 _value) checkGranularity(_value) public returns (bool) { - _adjustInvestorCount(msg.sender, address(0), _value); - require(tokenBurner != address(0), "Token Burner contract address is not set yet"); - require(_verifyTransfer(msg.sender, address(0), _value, true), "Transfer is not valid"); - require(_value <= balances[msg.sender], "Value should no be greater than the balance of msg.sender"); - _adjustBalanceCheckpoints(msg.sender); - _adjustTotalSupplyCheckpoints(); - // no need to require value <= totalSupply, since that would imply the - // sender's balance is greater than the totalSupply, which *should* be an assertion failure + require(_burn(msg.sender, _value)); + return true; + } - balances[msg.sender] = balances[msg.sender].sub(_value); - require(tokenBurner.burn(msg.sender, _value), "Token burner process is not validated"); - totalSupply_ = totalSupply_.sub(_value); - emit Burnt(msg.sender, _value); - emit Transfer(msg.sender, address(0), _value); + /** + * @notice Burn function used to burn the securityToken on behalf of someone else + * @param _from Address for whom to burn tokens + * @param _value No. of token that get burned + */ + function burnFrom(address _from, uint256 _value) checkGranularity(_value) public returns (bool) { + require(_value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + require(_burn(_from, _value)); + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); return true; } @@ -797,13 +816,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _data data attached to the transfer by controller to emit in event */ function forceTransfer(address _from, address _to, uint256 _value, bytes _data) public onlyController returns(bool) { - _adjustInvestorCount(_from, _to, _value); - bool verified = _verifyTransfer(_from, _to, _value, true); - _adjustBalanceCheckpoints(_from); - _adjustBalanceCheckpoints(_to); - require(_to != address(0)); require(_value <= balances[_from]); + bool verified = _updateTransfer(_from, _to, _value); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); From 825208e8f4ef443560e080cc8dc0875e9e406f63 Mon Sep 17 00:00:00 2001 From: satyam Date: Fri, 28 Sep 2018 13:24:12 +0530 Subject: [PATCH 09/63] some fixes --- contracts/ModuleRegistry.sol | 16 ++++++--- contracts/SecurityTokenRegistry.sol | 36 +++++++++++-------- contracts/mocks/SecurityTokenRegistryMock.sol | 5 ++- test/n_security_token_registry.js | 12 +++++++ 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index b9c72c0dd..c6b150385 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -69,7 +69,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { /** * @notice Modifier to make a function callable only when the contract is not paused. */ - modifier whenNotPaused() { + modifier whenNotPausedOrOwner() { if (msg.sender == getAddress(Encoder.getKey("owner"))) _; else { @@ -78,6 +78,14 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } } + /** + * @notice Modifier to make a function callable only when the contract is not paused and ignore is msg.sender is owner. + */ + modifier whenNotPaused() { + require(!getBool(Encoder.getKey("paused")), "Already paused"); + _; + } + /** * @notice Modifier to make a function callable only when the contract is paused. */ @@ -135,7 +143,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Called by the ModuleFactory owner to register new modules for SecurityTokens to use * @param _moduleFactory is the address of the module factory to be registered */ - function registerModule(address _moduleFactory) external whenNotPaused { + function registerModule(address _moduleFactory) external whenNotPausedOrOwner { require(getUint(Encoder.getKey('registry', _moduleFactory)) == 0, "Module factory should not be pre-registered"); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); uint8 moduleType = moduleFactory.getType(); @@ -150,7 +158,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Called by the ModuleFactory owner or registry curator to delete a ModuleFactory from the registry * @param _moduleFactory is the address of the module factory to be deleted from the registry */ - function removeModule(address _moduleFactory) external whenNotPaused { + function removeModule(address _moduleFactory) external whenNotPausedOrOwner { uint256 moduleType = getUint(Encoder.getKey('registry', _moduleFactory)); require(moduleType != 0, "Module factory should be registered"); @@ -300,7 +308,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { /** * @notice Called by the owner to pause, triggers stopped state */ - function pause() external onlyOwner { + function pause() external whenNotPaused onlyOwner { set(Encoder.getKey("paused"), true); emit Pause(now); } diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 7d265d988..1ae6193ff 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -115,7 +115,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { /** * @notice Modifier to make a function callable only when the contract is not paused. */ - modifier whenNotPaused() { + modifier whenNotPausedOrOwner() { if (msg.sender == getAddress(Encoder.getKey("owner"))) _; else { @@ -124,6 +124,14 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { } } + /** + * @notice Modifier to make a function callable only when the contract is not paused and ignore is msg.sender is owner. + */ + modifier whenNotPaused() { + require(!getBool(Encoder.getKey("paused")), "Already paused"); + _; + } + /** * @notice Modifier to make a function callable only when the contract is paused. @@ -154,7 +162,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function initialize(address _polymathRegistry, address _STFactory, uint256 _stLaunchFee, uint256 _tickerRegFee, address _polyToken, address _owner) payable external { require(!getBool(Encoder.getKey("initialised"))); - require(_STFactory != address(0) && _polyToken != address(0) && _owner != address(0) && _polymathRegistry != address(0), "0x address is in-valid"); + require(_STFactory != address(0) && _polyToken != address(0) && _owner != address(0) && _polymathRegistry != address(0), "In-valid address"); require(_stLaunchFee != 0 && _tickerRegFee != 0, "Fees should not be 0"); // address polyToken = _polyToken; set(Encoder.getKey("polyToken"), _polyToken); @@ -180,7 +188,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _ticker is unique token ticker * @param _tokenName is the name of the token */ - function registerTicker(address _owner, string _ticker, string _tokenName) external whenNotPaused { + function registerTicker(address _owner, string _ticker, string _tokenName) external whenNotPausedOrOwner { require(_owner != address(0), "Owner should not be 0x"); require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); // Attempt to charge the reg fee if it is > 0 POLY @@ -210,7 +218,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); require(_expiryDate != 0 && _registrationDate != 0, "Dates should not be 0"); require(_registrationDate <= _expiryDate, "Registration date should < expiry date"); - require(_owner != address(0), "Address should not be 0x"); + require(_owner != address(0), "In-valid address"); string memory ticker = Util.upper(_ticker); _modifyTicker(_owner, ticker, _tokenName, _registrationDate, _expiryDate, _status); } @@ -242,7 +250,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { function removeTicker(string _ticker) external onlyOwner { string memory ticker = Util.upper(_ticker); address owner = getAddress(Encoder.getKey("registeredTickers_owner", ticker)); - require(owner != address(0), "Ticker does not exist"); + require(owner != address(0), "Ticker doesn't exist"); _deleteTickerOwnership(owner, ticker); set(Encoder.getKey("tickerToSecurityToken", ticker), address(0)); _storeTickerDetails(ticker, address(0), 0, 0, "", false); @@ -309,9 +317,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _newOwner is the address of the new owner of the ticker * @param _ticker is the ticker symbol */ - function transferTickerOwnership(address _newOwner, string _ticker) external whenNotPaused { + function transferTickerOwnership(address _newOwner, string _ticker) external whenNotPausedOrOwner { string memory ticker = Util.upper(_ticker); - require(_newOwner != address(0), "Address should not be 0x"); + require(_newOwner != address(0), "In-valid address"); require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); _transferTickerOwnership(msg.sender, _newOwner, ticker); set(Encoder.getKey("registeredTickers_owner", ticker), _newOwner); @@ -325,7 +333,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function _transferTickerOwnership(address _oldOwner, address _newOwner, string _ticker) internal { if(getBool(Encoder.getKey("registeredTickers_status", _ticker))) - require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker))).owner() == _newOwner, "If the token exists, the ticker can only be transferred to its owner"); + require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker))).owner() == _newOwner, "Ticker can only be transferred to its token owner"); _deleteTickerOwnership(_oldOwner, _ticker); _setTickerOwner(_newOwner, _ticker); @@ -453,18 +461,18 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _tokenDetails is the off-chain details of the token * @param _divisible is whether or not the token is divisible */ - function generateSecurityToken(string _name, string _ticker, string _tokenDetails, bool _divisible) external whenNotPaused { + function generateSecurityToken(string _name, string _ticker, string _tokenDetails, bool _divisible) external whenNotPausedOrOwner { require(bytes(_name).length > 0 && bytes(_ticker).length > 0, "Ticker length > 0"); string memory ticker = Util.upper(_ticker); - require(getBool(Encoder.getKey("registeredTickers_status", ticker)) != true, "Ticker already deployed"); - require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Ticker and token should have same owner"); - require(getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker should not have expired"); + require(getBool(Encoder.getKey("registeredTickers_status", ticker)) != true, "Already deployed"); + require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); + require(getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker gets expired"); set(Encoder.getKey("registeredTickers_status", ticker), true); if (getUint(Encoder.getKey("stLaunchFee")) > 0) - require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("stLaunchFee"))), "Sufficent allowance is not provided"); + require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("stLaunchFee"))), "Insufficient allowance"); address newSecurityTokenAddress = ISTFactory(getSTFactoryAddress()).deployToken( _name, @@ -565,7 +573,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { /** * @notice called by the owner to pause, triggers stopped state */ - function pause() external onlyOwner { + function pause() external whenNotPaused onlyOwner { set(Encoder.getKey("paused"), true); emit Pause(now); } diff --git a/contracts/mocks/SecurityTokenRegistryMock.sol b/contracts/mocks/SecurityTokenRegistryMock.sol index e2b9bf2fd..78faa60d1 100644 --- a/contracts/mocks/SecurityTokenRegistryMock.sol +++ b/contracts/mocks/SecurityTokenRegistryMock.sol @@ -9,9 +9,8 @@ contract SecurityTokenRegistryMock is SecurityTokenRegistry { /// @notice It is dummy functionality /// Alert! Alert! Do not use it for the mainnet release - function changeTheDeployedAddress(string _ticker, address _newSecurityTokenAddress) public onlyOwner { - string memory __ticker = Util.upper(_ticker); - set(Encoder.getKey("tickerToSecurityToken", __ticker), _newSecurityTokenAddress); + function changeTheDeployedAddress(string _ticker, address _newSecurityTokenAddress) public { + set(Encoder.getKey("tickerToSecurityToken", _ticker), _newSecurityTokenAddress); } } diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index 3ccb90f8b..a53378c8b 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -383,6 +383,18 @@ contract('SecurityTokenRegistry', accounts => { assert.ok(errorThrown, message); }); + it("Should fail to pause if already paused", async() => { + let errorThrown = false; + try { + await I_STRProxied.pause({ from: account_polymath}); + } catch(error) { + console.log(` tx revert -> Registration is already paused`.grey); + errorThrown = true; + ensureException(error); + } + assert.ok(errorThrown, message); + }); + it("Should successfully register ticker if registration is unpaused", async() => { await I_STRProxied.unpause({ from: account_polymath}); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); From 4d6d16954077ab07b5d7e2e17e5033bf567b923f Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Fri, 28 Sep 2018 11:25:32 +0100 Subject: [PATCH 10/63] Updates --- contracts/tokens/SecurityToken.sol | 98 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 0b85e6762..7a62360a0 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -8,7 +8,6 @@ import "../interfaces/IModuleRegistry.sol"; import "../interfaces/IFeatureRegistry.sol"; import "../modules/TransferManager/ITransferManager.sol"; import "../modules/PermissionManager/IPermissionManager.sol"; -import "../interfaces/ITokenBurner.sol"; import "../RegistryUpdater.sol"; import "../libraries/Util.sol"; import "openzeppelin-solidity/contracts/ReentrancyGuard.sol"; @@ -42,8 +41,10 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint8 public constant PERMISSIONMANAGER_KEY = 1; uint8 public constant TRANSFERMANAGER_KEY = 2; - uint8 public constant STO_KEY = 3; + uint8 public constant MINT_KEY = 3; uint8 public constant CHECKPOINT_KEY = 4; + uint8 public constant BURN_KEY = 5; + uint256 public granularity; // Value of current checkpoint @@ -55,9 +56,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // List of token holders address[] public investors; - // Reference to token burner contract - ITokenBurner public tokenBurner; - // Use to temporarily halt all transactions bool public transfersFrozen; @@ -133,11 +131,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr event ChangeSTRAddress(address indexed _oldAddress, address indexed _newAddress); // Events to log minting and burning event Minted(address indexed _to, uint256 _value); - event Burnt(address indexed _burner, uint256 _value); + event Burnt(address indexed _from, uint256 _value); // Events to log controller actions event SetController(address indexed _oldController, address indexed _newController); event ForceTransfer(address indexed _controller, address indexed _from, address indexed _to, uint256 _value, bool _verifyTransfer, bytes _data); + event ForceBurn(address indexed _controller, address indexed _from, uint256 _value, bytes _data); event DisableController(uint256 _timestamp); function isModule(address _module, uint8 _type) internal view returns (bool) { @@ -622,7 +621,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value Number of tokens be minted * @return success */ - function mint(address _investor, uint256 _value) public onlyModuleOrOwner(STO_KEY) checkGranularity(_value) isMintingAllowed() returns (bool success) { + function mint(address _investor, uint256 _value) public onlyModuleOrOwner(MINT_KEY) checkGranularity(_value) isMintingAllowed() returns (bool success) { require(_investor != address(0), "Investor address should not be 0x"); _adjustInvestorCount(address(0), _investor, _value); require(_verifyTransfer(address(0), _investor, _value, true), "Transfer is not valid"); @@ -642,7 +641,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _values A list of number of tokens get minted and transfer to corresponding address of the investor from _investor[] list * @return success */ - function mintMulti(address[] _investors, uint256[] _values) external onlyModuleOrOwner(STO_KEY) returns (bool success) { + function mintMulti(address[] _investors, uint256[] _values) external onlyModuleOrOwner(MINT_KEY) returns (bool success) { require(_investors.length == _values.length, "Mis-match in the length of the arrays"); for (uint256 i = 0; i < _investors.length; i++) { mint(_investors[i], _values[i]); @@ -650,45 +649,11 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return true; } - /** - * @notice Validate permissions with PermissionManager if it exists, If no Permission return false - * @dev Note that IModule withPerm will allow ST owner all permissions anyway - * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) - * @param _delegate address of delegate - * @param _module address of PermissionManager module - * @param _perm the permissions - * @return success - */ - function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { - if (modules[PERMISSIONMANAGER_KEY].length == 0) { - return false; - } - - for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { - return true; - } - } - } - - /** - * @notice used to set the token Burner address. It only be called by the owner - * @param _tokenBurner Address of the token burner contract - */ - function setTokenBurner(address _tokenBurner) external onlyOwner { - tokenBurner = ITokenBurner(_tokenBurner); - } - function _burn(address _from, uint256 _value) internal returns (bool) { - require(tokenBurner != address(0), "Token Burner contract address is not set yet"); require(_value <= balances[_from], "Value too high"); - _updateTransfer(_from, address(0), _value); - - // no need to require value <= totalSupply, since that would imply the - // sender's balance is greater than the totalSupply, which *should* be an assertion failure + require(_updateTransfer(_from, address(0), _value), "Burn is not valid"); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); - require(tokenBurner.burn(_from, _value), "Token burner failed"); emit Burnt(_from, _value); emit Transfer(_from, address(0), _value); return true; @@ -696,9 +661,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr /** * @notice Burn function used to burn the securityToken - * @param _value No. of token that get burned + * @param _value No. of tokens that get burned */ - function burn(uint256 _value) checkGranularity(_value) public returns (bool) { + function burn(uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { require(_burn(msg.sender, _value)); return true; } @@ -706,10 +671,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr /** * @notice Burn function used to burn the securityToken on behalf of someone else * @param _from Address for whom to burn tokens - * @param _value No. of token that get burned + * @param _value No. of tokens that get burned */ - function burnFrom(address _from, uint256 _value) checkGranularity(_value) public returns (bool) { - require(_value <= balances[_from]); + function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { require(_value <= allowed[_from][msg.sender]); require(_burn(_from, _value)); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); @@ -727,6 +691,27 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return currentCheckpointId; } + /** + * @notice Validate permissions with PermissionManager if it exists, If no Permission return false + * @dev Note that IModule withPerm will allow ST owner all permissions anyway + * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) + * @param _delegate address of delegate + * @param _module address of PermissionManager module + * @param _perm the permissions + * @return success + */ + function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { + if (modules[PERMISSIONMANAGER_KEY].length == 0) { + return false; + } + + for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { + if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { + return true; + } + } + } + /** * @notice Queries totalSupply as of a defined checkpoint * @param _checkpointId Checkpoint ID to query @@ -827,6 +812,23 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return true; } + /** + * @notice Use by a controller to execute a foced burn + * @param _from address from which to take tokens + * @param _value amount of tokens to transfer + * @param _data data attached to the transfer by controller to emit in event + */ + function forceBurn(address _from, uint256 _value, bytes _data) public onlyController returns(bool) { + require(_value <= balances[_from], "Value too high"); + bool verified = _updateTransfer(_from, address(0), _value); + balances[_from] = balances[_from].sub(_value); + totalSupply_ = totalSupply_.sub(_value); + emit ForceBurn(msg.sender, _from, _value, _data); + emit Burnt(_from, _value); + emit Transfer(_from, address(0), _value); + return true; + } + /** * @notice Use to get the version of the securityToken */ From 3d75dda6810ac754eb7a7a0b1d79e58f6eb945a3 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Fri, 28 Sep 2018 11:56:58 +0100 Subject: [PATCH 11/63] Add an example redemption module --- contracts/modules/Burn/IBurn.sol | 8 ++ contracts/modules/Burn/TrackedRedemption.sol | 52 +++++++++ .../modules/Burn/TrackedRedemptionFactory.sol | 100 ++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 contracts/modules/Burn/IBurn.sol create mode 100644 contracts/modules/Burn/TrackedRedemption.sol create mode 100644 contracts/modules/Burn/TrackedRedemptionFactory.sol diff --git a/contracts/modules/Burn/IBurn.sol b/contracts/modules/Burn/IBurn.sol new file mode 100644 index 000000000..3af836f40 --- /dev/null +++ b/contracts/modules/Burn/IBurn.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.24; + +/** + * @title Interface to be implemented by all checkpoint modules + */ +interface IBurn { + +} diff --git a/contracts/modules/Burn/TrackedRedemption.sol b/contracts/modules/Burn/TrackedRedemption.sol new file mode 100644 index 000000000..f69d8a86a --- /dev/null +++ b/contracts/modules/Burn/TrackedRedemption.sol @@ -0,0 +1,52 @@ +pragma solidity ^0.4.24; + +import "./IBurn.sol"; +import "../Module.sol"; +import "../../interfaces/ISecurityToken.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; + +/** + * @title Burn module for burning tokens and keeping track of burnt amounts + */ +contract TrackedRedemption is IBurn, Module { + using SafeMath for uint256; + + mapping (address => uint256) redeemedTokens; + + event Redeemed(address _investor, 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 + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice This function returns the signature of configure function + */ + function getInitFunction() public pure returns (bytes4) { + return bytes4(0); + } + + /** + * @notice Redeem tokens and track redemptions + * @param _value The number of tokens to redeem + */ + function redeemTokens(uint256 _value) public { + require(ISecurityToken(securityToken).burnFrom(msg.sender, _value), "Unable to redeem tokens"); + redeemedTokens[msg.sender] = redeemedTokens[msg.sender].add(_value); + emit Redeemed(msg.sender, _value, now); + } + + /** + * @notice Return the permissions flag that are associated with CountTransferManager + */ + function getPermissions() public view returns(bytes32[]) { + bytes32[] memory allPermissions = new bytes32[](0); + return allPermissions; + } +} diff --git a/contracts/modules/Burn/TrackedRedemptionFactory.sol b/contracts/modules/Burn/TrackedRedemptionFactory.sol new file mode 100644 index 000000000..94003286b --- /dev/null +++ b/contracts/modules/Burn/TrackedRedemptionFactory.sol @@ -0,0 +1,100 @@ +pragma solidity ^0.4.24; + +import "./TrackedRedemption.sol"; +import "../ModuleFactory.sol"; + +/** + * @title Factory for deploying GeneralTransferManager module + */ +contract TrackedRedemptionFactory is ModuleFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + * @param _setupCost Setup cost of module + * @param _usageCost Usage cost of module + * @param _subscriptionCost Monthly cost of module + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + { + version = "1.0.0"; + name = "TrackedRedemption"; + title = "Tracked Redemption"; + description = "Track token redemptions"; + 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 + * @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"); + address trackedRedemption = new TrackedRedemption(msg.sender, address(polyToken)); + emit GenerateModuleFromFactory(address(trackedRedemption), getName(), address(this), msg.sender, setupCost, now); + return address(trackedRedemption); + } + + /** + * @notice Type of the Module factory + */ + function getType() public view returns(uint8) { + return 5; + } + + /** + * @notice Get the name of the Module + */ + function getName() public view returns(bytes32) { + return name; + } + + /** + * @notice Get the description of the Module + */ + function getDescription() public view returns(string) { + return description; + } + + /** + * @notice Get the version of the Module + */ + function getVersion() external view returns(string) { + return version; + } + + /** + * @notice Get the title of the Module + */ + function getTitle() public view returns(string) { + return title; + } + + /** + * @notice Get the setup cost of the module + */ + function getSetupCost() external view returns (uint256) { + return setupCost; + } + + /** + * @notice Get the Instructions that helped to used the module + */ + function getInstructions() public view returns(string) { + return "Allows an investor to redeem security tokens which are tracked by this module"; + } + + /** + * @notice Get the tags related to the module factory + */ + function getTags() public view returns(bytes32[]) { + bytes32[] memory availableTags = new bytes32[](2); + availableTags[0] = "Redemption"; + availableTags[1] = "Tracked"; + return availableTags; + } + +} From 8a1d8f989a3c4390d86e4bdb86dcd38c3953db3b Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Fri, 28 Sep 2018 09:26:32 -0300 Subject: [PATCH 12/63] Event names modified --- CLI/commands/ST20Generator.js | 8 ++++---- CLI/commands/contract_manager.js | 6 +++--- CLI/commands/dividends_manager.js | 4 ++-- CLI/commands/strMigrator.js | 2 +- CLI/commands/transfer_manager.js | 4 ++-- CLI/commands/whitelist.js | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index 1f15dc4c2..27ae398b2 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -144,7 +144,7 @@ async function step_ticker_reg(){ }); let transferTickerOwnershipAction = securityTokenRegistry.methods.transferTickerOwnership(newOwner, tokenSymbol); let receipt = await common.sendTransaction(Issuer, transferTickerOwnershipAction, defaultGasPrice, 0, 1.5); - let event = common.getEventFromLogs(securityTokenRegistry._jsonInterface, receipt.logs, 'LogChangeTickerOwnership'); + let event = common.getEventFromLogs(securityTokenRegistry._jsonInterface, receipt.logs, 'ChangeTickerOwnership'); console.log(chalk.green(`Ownership trasferred successfully. The new owner is ${event._newOwner}`)); process.exit(0); } @@ -187,7 +187,7 @@ async function step_token_deploy(){ await approvePoly(securityTokenRegistryAddress, launchFee); let generateSecurityTokenAction = securityTokenRegistry.methods.generateSecurityToken(tokenName, tokenSymbol, tokenDetails, divisibility); let receipt = await common.sendTransaction(Issuer, generateSecurityTokenAction, defaultGasPrice); - let event = common.getEventFromLogs(securityTokenRegistry._jsonInterface, receipt.logs, 'LogNewSecurityToken'); + let event = common.getEventFromLogs(securityTokenRegistry._jsonInterface, receipt.logs, 'NewSecurityToken'); console.log(`Deployed Token at address: ${event._securityTokenAddress}`); let securityTokenABI = abis.securityToken(); securityToken = new web3.eth.Contract(securityTokenABI, event._securityTokenAddress); @@ -444,7 +444,7 @@ async function cappedSTO_launch() { let addModuleAction = securityToken.methods.addModule(cappedSTOFactoryAddress, bytesSTO, new BigNumber(stoFee).times(new BigNumber(10).pow(18)), 0); let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice); - let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'LogModuleAdded'); + let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded'); console.log(`STO deployed at address: ${event._module}`); STO_Address = event._module; @@ -828,7 +828,7 @@ async function usdTieredSTO_launch() { let addModuleAction = securityToken.methods.addModule(usdTieredSTOFactoryAddress, bytesSTO, new BigNumber(stoFee).times(new BigNumber(10).pow(18)), 0); let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice); - let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'LogModuleAdded'); + let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded'); console.log(`STO deployed at address: ${event._module}`); STO_Address = event._module; diff --git a/CLI/commands/contract_manager.js b/CLI/commands/contract_manager.js index 9f8cf6812..60af89396 100644 --- a/CLI/commands/contract_manager.js +++ b/CLI/commands/contract_manager.js @@ -173,7 +173,7 @@ async function strActions() { let newExpiryLimit = duration.days(readlineSync.questionInt('Enter a new value in days for expiry limit: ')); let changeExpiryLimitAction = currentContract.methods.changeExpiryLimit(newExpiryLimit); let changeExpiryLimitReceipt = await common.sendTransaction(Issuer, changeExpiryLimitAction, defaultGasPrice); - let changeExpiryLimitEvent = common.getEventFromLogs(currentContract._jsonInterface, changeExpiryLimitReceipt.logs, 'LogChangeExpiryLimit'); + let changeExpiryLimitEvent = common.getEventFromLogs(currentContract._jsonInterface, changeExpiryLimitReceipt.logs, 'ChangeExpiryLimit'); console.log(chalk.green(`Expiry limit was changed successfuly. New limit is ${Math.floor(parseInt(changeExpiryLimitEvent._newExpiry)/60/60/24)} days\n`)); break; case 'Change registration fee': @@ -182,7 +182,7 @@ async function strActions() { let newRegFee = web3.utils.toWei(readlineSync.questionInt('Enter a new value in POLY for ticker registration fee: ').toString()); let changeRegFeeAction = currentContract.methods.changeTickerRegistrationFee(newRegFee); let changeRegFeeReceipt = await common.sendTransaction(Issuer, changeRegFeeAction, defaultGasPrice); - let changeRegFeeEvent = common.getEventFromLogs(currentContract._jsonInterface, changeRegFeeReceipt.logs, 'LogChangeTickerRegistrationFee'); + let changeRegFeeEvent = common.getEventFromLogs(currentContract._jsonInterface, changeRegFeeReceipt.logs, 'ChangeTickerRegistrationFee'); console.log(chalk.green(`Fee was changed successfuly. New fee is ${web3.utils.fromWei(changeRegFeeEvent._newFee)} POLY\n`)); break; case 'Change ST launch fee': @@ -191,7 +191,7 @@ async function strActions() { let newLaunchFee = web3.utils.toWei(readlineSync.questionInt('Enter a new value in POLY for ST launch fee: ').toString()); let changeLaunchFeeAction = currentContract.methods.changeSecurityLaunchFee(newLaunchFee); let changeLaunchFeeReceipt = await common.sendTransaction(Issuer, changeLaunchFeeAction, defaultGasPrice); - let changeLaunchFeeEvent = common.getEventFromLogs(currentContract._jsonInterface, changeLaunchFeeReceipt.logs, 'LogChangeSecurityLaunchFee'); + let changeLaunchFeeEvent = common.getEventFromLogs(currentContract._jsonInterface, changeLaunchFeeReceipt.logs, 'ChangeSecurityLaunchFee'); console.log(chalk.green(`Fee was changed successfuly. New fee is ${web3.utils.fromWei(changeLaunchFeeEvent._newFee)} POLY\n`)); break; case 'CANCEL': diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index bc30dddf9..bd43d6661 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -475,7 +475,7 @@ async function addDividendsModule() { let addModuleAction = securityToken.methods.addModule(dividendsFactoryAddress, web3.utils.fromAscii('', 16), 0, 0); let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice); - let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'LogModuleAdded'); + let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded'); console.log(`Module deployed at address: ${event._module}`); currentDividendsModule = new web3.eth.Contract(dividendsModuleABI, event._module); currentDividendsModule.setProvider(web3.currentProvider); @@ -504,7 +504,7 @@ async function getCheckpoints() { } */ - let events = await securityToken.getPastEvents('LogCheckpointCreated', { fromBlock: 0}); + let events = await securityToken.getPastEvents('CheckpointCreated', { fromBlock: 0}); for (let event of events) { let checkpoint = {}; checkpoint.id = event.returnValues._checkpointId; diff --git a/CLI/commands/strMigrator.js b/CLI/commands/strMigrator.js index d0538dbad..a2ba4bdf0 100644 --- a/CLI/commands/strMigrator.js +++ b/CLI/commands/strMigrator.js @@ -80,7 +80,7 @@ function step_instance_toSTR(toStrAddress){ async function step_get_deployed_tokens(securityTokenRegistry) { let tokens = []; - let events = await securityTokenRegistry.getPastEvents('LogNewSecurityToken', { fromBlock: 0}); + let events = await securityTokenRegistry.getPastEvents('NewSecurityToken', { fromBlock: 0}); if (events.length == 0) { console.log("No security token events were emitted."); } else { diff --git a/CLI/commands/transfer_manager.js b/CLI/commands/transfer_manager.js index 9d9b46f29..0769f88aa 100644 --- a/CLI/commands/transfer_manager.js +++ b/CLI/commands/transfer_manager.js @@ -85,7 +85,7 @@ async function start_explorer() { }); let setControllerAction = securityToken.methods.setController(controllerAddress); let setControllerReceipt = await common.sendTransaction(Issuer, setControllerAction, defaultGasPrice); - let setControllerEvent = common.getEventFromLogs(securityToken._jsonInterface, setControllerReceipt.logs, 'LogSetController'); + let setControllerEvent = common.getEventFromLogs(securityToken._jsonInterface, setControllerReceipt.logs, 'SetController'); console.log(chalk.green(`New controller is ${setControllerEvent._newController}`)); break; case 'Force Transfer': @@ -114,7 +114,7 @@ async function start_explorer() { let data = readlineSync.question('Enter the data attached to the transfer by controller to emit in event: '); let forceTransferAction = securityToken.methods.forceTransfer(from, to, web3.utils.toWei(amount), web3.utils.asciiToHex(data)); let forceTransferReceipt = await common.sendTransaction(Issuer, forceTransferAction, defaultGasPrice, 0, 1.5); - let forceTransferEvent = common.getEventFromLogs(securityToken._jsonInterface, forceTransferReceipt.logs, 'LogForceTransfer'); + let forceTransferEvent = common.getEventFromLogs(securityToken._jsonInterface, forceTransferReceipt.logs, 'ForceTransfer'); console.log(chalk.green(` ${forceTransferEvent._controller} has successfully forced a transfer of ${web3.utils.fromWei(forceTransferEvent._amount)} ${tokenSymbol} from ${forceTransferEvent._from} to ${forceTransferEvent._to} Verified transfer: ${forceTransferEvent._verifyTransfer} diff --git a/CLI/commands/whitelist.js b/CLI/commands/whitelist.js index 26f4af32a..903ef40ec 100644 --- a/CLI/commands/whitelist.js +++ b/CLI/commands/whitelist.js @@ -185,7 +185,7 @@ async function setInvestors() { let investorData_Events = new Array(); let investorObjectLookup = {}; - let event_data = await generalTransferManager.getPastEvents('LogModifyWhitelist', { + let event_data = await generalTransferManager.getPastEvents('ModifyWhitelist', { fromBlock: 0, toBlock: 'latest' }, function (error, events) { From fe71172dd5abe161e7211d997b4ea10bd4d737b3 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Fri, 28 Sep 2018 09:33:24 -0300 Subject: [PATCH 13/63] Fix for calculate dividend --- CLI/commands/dividends_manager.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index bd43d6661..59b0d748a 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -157,11 +157,14 @@ async function start_explorer(){ let _address3 = readlineSync.question('Enter address to explore: '); let _dividend3 = await selectDividend(); if (_dividend3 !== null) { - let divsBalance = await currentDividendsModule.methods.calculateDividend(_dividend3.index, _address3).call(); + let dividendAmounts = await currentDividendsModule.methods.calculateDividend(_dividend3.index, _address3).call(); + let dividendBalance = dividendAmounts[0]; + let dividendTax = dividendAmounts[1]; let balance = await getBalance(_address3); console.log(` ${dividendsType} Balance: ${web3.utils.fromWei(balance)} ${dividendsType} - Dividends owned: ${web3.utils.fromWei(divsBalance)} ${dividendsType} + Dividends owned: ${web3.utils.fromWei(dividendBalance)} ${dividendsType} + Tax withheld: ${web3.utils.fromWei(dividendTax)} ${dividendsType} `); } break; From 147d7cd87ea0c6bdeeb36c2eebfd5d270c0dbb1e Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Fri, 28 Sep 2018 11:23:14 -0300 Subject: [PATCH 14/63] Coverage fix for TravisCI --- .solcover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.solcover.js b/.solcover.js index 47f4c173b..32cb416b2 100644 --- a/.solcover.js +++ b/.solcover.js @@ -2,7 +2,7 @@ module.exports = { norpc: true, port: 8545, copyPackages: ['openzeppelin-solidity'], - testCommand: 'node ../node_modules/.bin/truffle test `find test/*.js ! -name a_poly_oracle.js` --network coverage', + 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'] }; From 23f5f98b8c7ed6c959a89bcb3a5044a45cb7c7bf Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Fri, 28 Sep 2018 19:25:39 +0100 Subject: [PATCH 15/63] Optimisations --- contracts/SecurityTokenRegistry.sol | 211 +++++++++--------- contracts/interfaces/IOwnable.sol | 2 +- .../interfaces/ISecurityTokenRegistry.sol | 2 +- contracts/tokens/SecurityToken.sol | 7 +- 4 files changed, 106 insertions(+), 116 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 1ae6193ff..9ec100df1 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -116,8 +116,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPausedOrOwner() { - if (msg.sender == getAddress(Encoder.getKey("owner"))) - _; + if (msg.sender == getAddress(Encoder.getKey("owner"))) + _; else { require(!getBool(Encoder.getKey("paused")), "Already paused"); _; @@ -145,12 +145,6 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { // Initialization ///////////////////////////// - // Constructor - constructor () public - { - - } - /** * @notice initializes instance of STR * @param _polymathRegistry is the address of the Polymath Registry @@ -162,9 +156,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function initialize(address _polymathRegistry, address _STFactory, uint256 _stLaunchFee, uint256 _tickerRegFee, address _polyToken, address _owner) payable external { require(!getBool(Encoder.getKey("initialised"))); - require(_STFactory != address(0) && _polyToken != address(0) && _owner != address(0) && _polymathRegistry != address(0), "In-valid address"); + require(_STFactory != address(0) && _polyToken != address(0) && _owner != address(0) && _polymathRegistry != address(0), "Invalid address"); require(_stLaunchFee != 0 && _tickerRegFee != 0, "Fees should not be 0"); - // address polyToken = _polyToken; set(Encoder.getKey("polyToken"), _polyToken); set(Encoder.getKey("stLaunchFee"), _stLaunchFee); set(Encoder.getKey("tickerRegFee"), _tickerRegFee); @@ -172,7 +165,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { set(Encoder.getKey("paused"), false); set(Encoder.getKey("owner"), _owner); set(Encoder.getKey("polymathRegistry"), _polymathRegistry); - _setProtocolVersion(_STFactory, uint8(0), uint8(0), uint8(2)); + setProtocolVersion(_STFactory, uint8(0), uint8(0), uint8(2)); set(Encoder.getKey("initialised"), true); } @@ -192,18 +185,28 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_owner != address(0), "Owner should not be 0x"); require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); // Attempt to charge the reg fee if it is > 0 POLY - if (getUint(Encoder.getKey("tickerRegFee")) > 0) - require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("tickerRegFee"))), "Sufficent allowance is not provided"); + uint256 tickerFee = getUint(Encoder.getKey("tickerRegFee")); + if (tickerFee > 0) + require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), tickerFee), "Insufficent allowance"); string memory ticker = Util.upper(_ticker); - require(_tickerAvailable(ticker), "Ticker is already reserved"); + require(_tickerAvailable(ticker), "Ticker is reserved"); // Check whether ticker was previously registered (and expired) - address previousOwner = getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); + address previousOwner = getAddress(Encoder.getKey("registeredTickers_owner", ticker)); if (previousOwner != address(0)) { - _deleteTickerOwnership(previousOwner, _ticker); + _deleteTickerOwnership(previousOwner, ticker); } _addTicker(_owner, ticker, _tokenName, now, now.add(getUint(Encoder.getKey("expiryLimit"))), false, false); } + /** + * @notice Internal - Sets the details of the ticker + */ + function _addTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status, bool _fromAdmin) internal { + _setTickerOwnership(_owner, _ticker); + _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); + emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _fromAdmin); + } + /** * @notice Modifies the ticker details. Only Polymath has the ability to do so. * @notice Only allowed to modify the tickers which are not yet deployed. @@ -218,7 +221,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); require(_expiryDate != 0 && _registrationDate != 0, "Dates should not be 0"); require(_registrationDate <= _expiryDate, "Registration date should < expiry date"); - require(_owner != address(0), "In-valid address"); + require(_owner != address(0), "Invalid address"); string memory ticker = Util.upper(_ticker); _modifyTicker(_owner, ticker, _tokenName, _registrationDate, _expiryDate, _status); } @@ -228,19 +231,13 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function _modifyTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status) internal { address currentOwner = getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); - if (currentOwner == address(0) && _registrationDate == 0 && _expiryDate == 0) { - _addTicker(_owner, _ticker, _tokenName, now, now.add(getUint(Encoder.getKey("expiryLimit"))), _status, true); - return; - } - // If ticker exists, and is registered to a different owner, switch over - if ((currentOwner != address(0)) && (currentOwner != _owner)) { - _transferTickerOwnership(currentOwner, _owner, _ticker); + if (currentOwner != address(0)) { + _deleteTickerOwnership(currentOwner, _ticker); } - if (getBool(Encoder.getKey("registeredTickers_status", _ticker)) && !_status) { + if (_tickerStatus(_ticker) && !_status) { set(Encoder.getKey("tickerToSecurityToken", _ticker), address(0)); } - _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); - emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, true); + _addTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _status, true); } /** @@ -254,7 +251,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { _deleteTickerOwnership(owner, ticker); set(Encoder.getKey("tickerToSecurityToken", ticker), address(0)); _storeTickerDetails(ticker, address(0), 0, 0, "", false); - emit TickerRemoved(_ticker, now, msg.sender); + emit TickerRemoved(ticker, now, msg.sender); } /** @@ -264,7 +261,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function _tickerAvailable(string _ticker) internal view returns(bool) { if (getAddress(Encoder.getKey("registeredTickers_owner", _ticker)) != address(0)) { - if (now > getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker)) && !getBool(Encoder.getKey("registeredTickers_status", _ticker))) { + if ((now > getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker))) && !_tickerStatus(_ticker)) { return true; } else return false; @@ -272,13 +269,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return true; } - /** - * @notice Internal - Sets the details of the ticker - */ - function _addTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status, bool _fromAdmin) internal { - _setTickerOwner(_owner, _ticker); - _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); - emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _fromAdmin); + function _tickerStatus(string _ticker) internal returns(bool) { + return getBool(Encoder.getKey("registeredTickers_status", _ticker)); } /** @@ -286,13 +278,14 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _owner is the address of the owner of the ticker * @param _ticker is the ticker symbol */ - function _setTickerOwner(address _owner, string _ticker) internal { + function _setTickerOwnership(address _owner, string _ticker) internal { uint256 length = uint256(getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length); pushArray(Encoder.getKey("userToTickers", _owner), Util.stringToBytes32(_ticker)); set(Encoder.getKey("tickerIndex", _ticker), length); - if (!getBool(Encoder.getKey("seenUsers", _owner))) { + bytes32 seenKey = Encoder.getKey("seenUsers", _owner); + if (!getBool(seenKey)) { pushArray(Encoder.getKey("activeUsers"), _owner); - set(Encoder.getKey("seenUsers", _owner), true); + set(seenKey, true); } } @@ -300,16 +293,21 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Internal - Stores the ticker details */ function _storeTickerDetails(string _ticker, address _owner, uint256 _registrationDate, uint256 _expiryDate, string _tokenName, bool _status) internal { - if (getAddress(Encoder.getKey("registeredTickers_owner", _ticker)) != _owner) - set(Encoder.getKey("registeredTickers_owner", _ticker), _owner); - if (getUint(Encoder.getKey("registeredTickers_registrationDate", _ticker)) != _registrationDate) - set(Encoder.getKey("registeredTickers_registrationDate", _ticker), _registrationDate); - if (getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker)) != _expiryDate) - set(Encoder.getKey("registeredTickers_expiryDate", _ticker), _expiryDate); - if (Encoder.getKey(getString(Encoder.getKey("registeredTickers_tokenName", _ticker))) != Encoder.getKey(_tokenName)) - set(Encoder.getKey("registeredTickers_tokenName", _ticker), _tokenName); - if (getBool(Encoder.getKey("registeredTickers_status", _ticker)) != _status) - set(Encoder.getKey("registeredTickers_status", _ticker), _status); + bytes32 key = Encoder.getKey("registeredTickers_owner", _ticker); + if (getAddress(key) != _owner) + set(key, _owner); + key = Encoder.getKey("registeredTickers_registrationDate", _ticker); + if (getUint(key) != _registrationDate) + set(key, _registrationDate); + key = Encoder.getKey("registeredTickers_expiryDate", _ticker); + if (getUint(key) != _expiryDate) + set(key, _expiryDate); + key = Encoder.getKey("registeredTickers_tokenName", _ticker); + if (Encoder.getKey(getString(key)) != Encoder.getKey(_tokenName)) + set(key, _tokenName); + key = Encoder.getKey("registeredTickers_status", _ticker); + if (getBool(key) != _status) + set(key, _status); } /** @@ -319,39 +317,29 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function transferTickerOwnership(address _newOwner, string _ticker) external whenNotPausedOrOwner { string memory ticker = Util.upper(_ticker); - require(_newOwner != address(0), "In-valid address"); - require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); - _transferTickerOwnership(msg.sender, _newOwner, ticker); - set(Encoder.getKey("registeredTickers_owner", ticker), _newOwner); - } - - /** - * @notice Internal - Transfers the control of ticker to a newOwner - * @param _oldOwner is the previous owner - * @param _newOwner is the the new owner - * @param _ticker is the ticker symbol - */ - function _transferTickerOwnership(address _oldOwner, address _newOwner, string _ticker) internal { - if(getBool(Encoder.getKey("registeredTickers_status", _ticker))) - require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker))).owner() == _newOwner, "Ticker can only be transferred to its token owner"); - - _deleteTickerOwnership(_oldOwner, _ticker); - _setTickerOwner(_newOwner, _ticker); - emit ChangeTickerOwnership(_ticker, _oldOwner, _newOwner); + require(_newOwner != address(0), "Invalid address"); + bytes32 ownerKey = Encoder.getKey("registeredTickers_owner", ticker); + require(getAddress(ownerKey) == msg.sender, "Not authorised"); + if (_tickerStatus(ticker)) + require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", ticker))).owner() == _newOwner, "New owner does not match token owner"); + set(ownerKey, _newOwner); + _deleteTickerOwnership(msg.sender, ticker); + _setTickerOwnership(_newOwner, ticker); + emit ChangeTickerOwnership(ticker, msg.sender, _newOwner); } /** * @notice Internal - Removes the owner of a ticker */ function _deleteTickerOwnership(address _owner, string _ticker) internal { - uint256 _index = uint256(getUint(Encoder.getKey("tickerIndex", _ticker))); - assert(_index < getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length); - // deleting the _index from the data strucutre userToTickers[_oldowner][_index]; - deleteArrayBytes32(Encoder.getKey("userToTickers", _owner), _index); - - if (getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length > _index) { - bytes32 switchedTicker = getArrayBytes32(Encoder.getKey("userToTickers", _owner))[_index]; - set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), _index); + uint256 index = uint256(getUint(Encoder.getKey("tickerIndex", _ticker))); + bytes32 ownerKey = Encoder.getKey("userToTickers", _owner); + bytes32[] memory tickers = getArrayBytes32(ownerKey); + assert(index < tickers.length); + deleteArrayBytes32(Encoder.getKey("userToTickers", _owner), index); + if (tickers.length > index) { + bytes32 switchedTicker = tickers[index]; + set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), index); } } @@ -361,8 +349,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function changeExpiryLimit(uint256 _newExpiry) external onlyOwner { require(_newExpiry >= 1 days, "Expiry should >= 1 day"); - emit ChangeExpiryLimit(getUint(Encoder.getKey('expiryLimit')), _newExpiry); - set(Encoder.getKey('expiryLimit'), _newExpiry); + bytes32 key = Encoder.getKey('expiryLimit'); + emit ChangeExpiryLimit(getUint(key), _newExpiry); + set(key, _newExpiry); } /** @@ -372,12 +361,12 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { function getTickersByOwner(address _owner) external view returns(bytes32[]) { uint counter = 0; // accessing the data structure userTotickers[_owner].length - uint _len = getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length; - bytes32[] memory tempList = new bytes32[](_len); - for (uint i = 0; i < _len; i++) { - string memory _ticker = Util.bytes32ToString(getArrayBytes32(Encoder.getKey("userToTickers", _owner))[i]); - if (getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker)) >= now || getBool(Encoder.getKey("registeredTickers_status", _ticker))) { - tempList[counter] = getArrayBytes32(Encoder.getKey("userToTickers", _owner))[i]; + bytes32[] memory tickers = getArrayBytes32(Encoder.getKey("userToTickers", _owner)); + bytes32[] memory tempList = new bytes32[](tickers.length); + for (uint i = 0; i < tickers.length; i++) { + string memory ticker = Util.bytes32ToString(tickers[i]); + if (getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now || _tickerStatus(ticker)) { + tempList[counter] = tickers[i]; counter ++; } } @@ -437,14 +426,16 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function getTickerDetails(string _ticker) external view returns (address, uint256, uint256, string, bool) { string memory ticker = Util.upper(_ticker); - if (getBool(Encoder.getKey("registeredTickers_status", ticker)) == true || getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) > now) { + bool tickerStatus = _tickerStatus(ticker); + uint256 expiryDate = getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)); + if ((tickerStatus == true) || (expiryDate > now)) { return ( getAddress(Encoder.getKey("registeredTickers_owner", ticker)), getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), - getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)), + expiryDate, getString(Encoder.getKey("registeredTickers_tokenName", ticker)), - getBool(Encoder.getKey("registeredTickers_status", ticker)) + tickerStatus ); } else return (address(0), uint256(0), uint256(0), "", false); @@ -464,15 +455,15 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { function generateSecurityToken(string _name, string _ticker, string _tokenDetails, bool _divisible) external whenNotPausedOrOwner { require(bytes(_name).length > 0 && bytes(_ticker).length > 0, "Ticker length > 0"); string memory ticker = Util.upper(_ticker); - - require(getBool(Encoder.getKey("registeredTickers_status", ticker)) != true, "Already deployed"); + bytes32 statusKey = Encoder.getKey("registeredTickers_status", ticker); + require(getBool(statusKey) != true, "Already deployed"); + set(statusKey, true); require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); require(getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker gets expired"); - set(Encoder.getKey("registeredTickers_status", ticker), true); - - if (getUint(Encoder.getKey("stLaunchFee")) > 0) - require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), getUint(Encoder.getKey("stLaunchFee"))), "Insufficient allowance"); + uint256 launchFee = getUint(Encoder.getKey("stLaunchFee")); + if (launchFee > 0) + require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), launchFee), "Insufficient allowance"); address newSecurityTokenAddress = ISTFactory(getSTFactoryAddress()).deployToken( _name, @@ -566,8 +557,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { */ function transferOwnership(address _newOwner) external onlyOwner { require(_newOwner != address(0)); - emit OwnershipTransferred(getAddress(Encoder.getKey("owner")), _newOwner); - set(Encoder.getKey("owner"), _newOwner); + bytes32 key = Encoder.getKey("owner"); + emit OwnershipTransferred(getAddress(key), _newOwner); + set(key, _newOwner); } /** @@ -591,9 +583,11 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _tickerRegFee is the registration fee in POLY tokens (base 18 decimals) */ function changeTickerRegistrationFee(uint256 _tickerRegFee) external onlyOwner { - require(getUint(Encoder.getKey('tickerRegFee')) != _tickerRegFee); - emit ChangeTickerRegistrationFee(getUint(Encoder.getKey('tickerRegFee')), _tickerRegFee); - set(Encoder.getKey('tickerRegFee'), _tickerRegFee); + bytes32 key = Encoder.getKey('tickerRegFee'); + uint256 fee = getUint(key); + require(fee != _tickerRegFee); + emit ChangeTickerRegistrationFee(fee, _tickerRegFee); + set(key, _tickerRegFee); } /** @@ -601,9 +595,11 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _stLaunchFee is the registration fee in POLY tokens (base 18 decimals) */ function changeSecurityLaunchFee(uint256 _stLaunchFee) external onlyOwner { - require(getUint(Encoder.getKey("stLaunchFee")) != _stLaunchFee); - emit ChangeSecurityLaunchFee(getUint(Encoder.getKey("stLaunchFee")), _stLaunchFee); - set(Encoder.getKey("stLaunchFee"), _stLaunchFee); + bytes32 key = Encoder.getKey('stLaunchFee'); + uint256 fee = getUint(key); + require(fee != _stLaunchFee); + emit ChangeSecurityLaunchFee(fee, _stLaunchFee); + set(key, _stLaunchFee); } /** @@ -626,22 +622,15 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _minor Minor version of the proxy. * @param _patch Patch version of the proxy */ - function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) external onlyOwner { - _setProtocolVersion(_STFactoryAddress, _major, _minor, _patch); - } - - /** - * @notice Internal - Changes the protocol version and the SecurityToken contract - */ - function _setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) internal { + function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) public onlyOwner { uint8[] memory _version = new uint8[](3); _version[0] = _major; _version[1] = _minor; _version[2] = _patch; uint24 _packedVersion = VersionUtils.pack(_major, _minor, _patch); - require(VersionUtils.isValidVersion(getProtocolVersion(), _version),"In-valid version"); + require(VersionUtils.isValidVersion(getProtocolVersion(), _version),"Invalid version"); set(Encoder.getKey("latestVersion"), uint256(_packedVersion)); - set(Encoder.getKey("protocolVersionST", getUint(Encoder.getKey("latestVersion"))), _STFactoryAddress); + set(Encoder.getKey("protocolVersionST", uint256(_packedVersion)), _STFactoryAddress); } /** diff --git a/contracts/interfaces/IOwnable.sol b/contracts/interfaces/IOwnable.sol index 15849e181..de8a8d14f 100644 --- a/contracts/interfaces/IOwnable.sol +++ b/contracts/interfaces/IOwnable.sol @@ -10,7 +10,7 @@ interface IOwnable { /** * @dev Returns owner */ - function owner() external returns (address); + function owner() external view returns (address); /** * @dev Allows the current owner to relinquish control of the contract. diff --git a/contracts/interfaces/ISecurityTokenRegistry.sol b/contracts/interfaces/ISecurityTokenRegistry.sol index 444fb5375..d7ec8f9f0 100644 --- a/contracts/interfaces/ISecurityTokenRegistry.sol +++ b/contracts/interfaces/ISecurityTokenRegistry.sol @@ -84,7 +84,7 @@ interface ISecurityTokenRegistry { /** * @notice get Protocol version */ - function getProtocolVersion() public view returns(uint8[]); + function getProtocolVersion() external view returns(uint8[]); /** * @notice Use to get the ticker list as per the owner diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 137ffc30b..6c866a7df 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -99,6 +99,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Records added module names - module list should be order agnostic! mapping (bytes32 => address[]) names; + // List of investors mapping (address => bool) public investorListed; // Emit at the time when module get added @@ -141,7 +142,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr event ForceTransfer(address indexed _controller, address indexed _from, address indexed _to, uint256 _amount, bool _verifyTransfer, bytes _data); event DisableController(uint256 _timestamp); - function isModule(address _module, uint8 _type) internal view returns (bool) { + function _isModule(address _module, uint8 _type) internal view returns (bool) { require(modulesToData[_module].module == _module, "Address mismatch"); require(modulesToData[_module].moduleType == _type, "Type mismatch"); require(!modulesToData[_module].isArchived, "Module archived"); @@ -150,7 +151,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Require msg.sender to be the specified module type modifier onlyModule(uint8 _type) { - require(isModule(msg.sender, _type)); + require(_isModule(msg.sender, _type)); _; } @@ -159,7 +160,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr if (msg.sender == owner) { _; } else { - require(isModule(msg.sender, _type)); + require(_isModule(msg.sender, _type)); _; } } From 0fd563733dee9fdb7c2b5fcf8c9abb5bfd4060ae Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Fri, 28 Sep 2018 16:04:47 -0300 Subject: [PATCH 16/63] CLI: Get factories address from ModuleRegistry --- CLI/commands/ST20Generator.js | 56 +-- CLI/commands/dividends_manager.js | 16 +- CLI/commands/helpers/contract_abis.js | 16 +- CLI/commands/helpers/contract_addresses.js | 63 +-- demo/checkpoint/ethExplorer.js | 543 --------------------- 5 files changed, 73 insertions(+), 621 deletions(-) delete mode 100644 demo/checkpoint/ethExplorer.js diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index 27ae398b2..ae8466ad0 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -9,8 +9,6 @@ var common = require('./common/common_functions'); var global = require('./common/global'); let securityTokenRegistryAddress; -let cappedSTOFactoryAddress; -let usdTieredSTOFactoryAddress; /////////////////// // Crowdsale params @@ -18,7 +16,13 @@ let tokenName; let tokenSymbol; let selectedSTO; -const STO_KEY = 3; +const MODULES_TYPES = { + PERMISSION: 1, + TRANSFER: 2, + STO: 3, + DIVIDENDS: 4 +} + const REG_FEE_KEY = 'tickerRegFee'; const LAUNCH_FEE_KEY = 'stLaunchFee'; const cappedSTOFee = 20000; @@ -37,8 +41,6 @@ let usdToken; let securityToken; let generalTransferManager; let currentSTO; -let cappedSTOFactory; -let usdTieredSTOFactory; // App flow let _tokenConfig; @@ -90,16 +92,6 @@ async function setup(){ let usdTokenAddress = await contracts.usdToken(); usdToken = new web3.eth.Contract(polytokenABI, usdTokenAddress); usdToken.setProvider(web3.currentProvider); - - cappedSTOFactoryAddress = await contracts.cappedSTOFactoryAddress(); - let cappedSTOFactoryABI = abis.cappedSTOFactory(); - cappedSTOFactory = new web3.eth.Contract(cappedSTOFactoryABI, cappedSTOFactoryAddress); - cappedSTOFactory.setProvider(web3.currentProvider); - - usdTieredSTOFactoryAddress = await contracts.usdTieredSTOFactoryAddress(); - let usdTieredSTOFactoryABI = abis.usdTieredSTOFactory(); - usdTieredSTOFactory = new web3.eth.Contract(usdTieredSTOFactoryABI, usdTieredSTOFactoryAddress); - usdTieredSTOFactory.setProvider(web3.currentProvider); } catch (err) { console.log(err) console.log('\x1b[31m%s\x1b[0m',"There was a problem getting the contracts. Make sure they are deployed to the selected network."); @@ -111,6 +103,7 @@ async function step_ticker_reg(){ console.log('\n\x1b[34m%s\x1b[0m',"Token Creation - Symbol Registration"); let available = false; + let isDeployed; let regFee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); while (!available) { @@ -123,6 +116,7 @@ async function step_ticker_reg(){ } let details = await securityTokenRegistry.methods.getTickerDetails(tokenSymbol).call(); + isDeployed = details[4]; if (new BigNumber(details[1]).toNumber() == 0) { available = true; await approvePoly(securityTokenRegistryAddress, regFee); @@ -135,18 +129,20 @@ async function step_ticker_reg(){ } } - if (typeof _tokenConfig === 'undefined' && readlineSync.keyInYNStrict(`Do you want to transfer the ownership of ${tokenSymbol} ticker?`)) { - let newOwner = readlineSync.question('Enter the address that will be the new owner: ', { - limit: function(input) { - return web3.utils.isAddress(input); - }, - limitMessage: "Must be a valid address" - }); - let transferTickerOwnershipAction = securityTokenRegistry.methods.transferTickerOwnership(newOwner, tokenSymbol); - let receipt = await common.sendTransaction(Issuer, transferTickerOwnershipAction, defaultGasPrice, 0, 1.5); - let event = common.getEventFromLogs(securityTokenRegistry._jsonInterface, receipt.logs, 'ChangeTickerOwnership'); - console.log(chalk.green(`Ownership trasferred successfully. The new owner is ${event._newOwner}`)); - process.exit(0); + if (!isDeployed) { + if (typeof _tokenConfig === 'undefined' && readlineSync.keyInYNStrict(`Do you want to transfer the ownership of ${tokenSymbol} ticker?`)) { + let newOwner = readlineSync.question('Enter the address that will be the new owner: ', { + limit: function(input) { + return web3.utils.isAddress(input); + }, + limitMessage: "Must be a valid address" + }); + let transferTickerOwnershipAction = securityTokenRegistry.methods.transferTickerOwnership(newOwner, tokenSymbol); + let receipt = await common.sendTransaction(Issuer, transferTickerOwnershipAction, defaultGasPrice, 0, 1.5); + let event = common.getEventFromLogs(securityTokenRegistry._jsonInterface, receipt.logs, 'ChangeTickerOwnership'); + console.log(chalk.green(`Ownership trasferred successfully. The new owner is ${event._newOwner}`)); + process.exit(0); + } } } @@ -195,7 +191,7 @@ async function step_token_deploy(){ } async function step_Wallet_Issuance(){ - let result = await securityToken.methods.getModulesByType(STO_KEY).call(); + let result = await securityToken.methods.getModulesByType(MODULES_TYPES.STO).call(); if (result.length > 0) { console.log('\x1b[32m%s\x1b[0m',"STO has already been created at address " + result[0] + ". Skipping initial minting"); } else { @@ -275,7 +271,7 @@ async function step_STO_launch() { console.log("\n"); console.log('\x1b[34m%s\x1b[0m',"Token Creation - STO Configuration"); - let result = await securityToken.methods.getModulesByType(STO_KEY).call(); + let result = await securityToken.methods.getModulesByType(MODULES_TYPES.STO).call(); if (result.length > 0) { STO_Address = result[0]; let stoModuleData = await securityToken.methods.getModule(STO_Address).call(); @@ -442,6 +438,7 @@ async function cappedSTO_launch() { ] }, [startTime, endTime, web3.utils.toWei(cap), rate, raiseType, wallet]); + let cappedSTOFactoryAddress = await contracts.getModuleFactoryAddressByName(securityToken.options.address, MODULES_TYPES.STO, "CappedSTO"); let addModuleAction = securityToken.methods.addModule(cappedSTOFactoryAddress, bytesSTO, new BigNumber(stoFee).times(new BigNumber(10).pow(18)), 0); let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice); let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded'); @@ -826,6 +823,7 @@ async function usdTieredSTO_launch() { addresses.usdToken ]); + let usdTieredSTOFactoryAddress = await contracts.getModuleFactoryAddressByName(securityToken.options.address, MODULES_TYPES.STO, 'USDTieredSTO'); let addModuleAction = securityToken.methods.addModule(usdTieredSTOFactoryAddress, bytesSTO, new BigNumber(stoFee).times(new BigNumber(10).pow(18)), 0); let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice); let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded'); diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index 59b0d748a..5222cb167 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -14,7 +14,12 @@ var global = require('./common/global'); var contracts = require('./helpers/contract_addresses'); var abis = require('./helpers/contract_abis'); -const STO_KEY = 3; +const MODULES_TYPES = { + PERMISSION: 1, + TRANSFER: 2, + STO: 3, + DIVIDENDS: 4 +} // App flow let tokenSymbol; @@ -188,7 +193,7 @@ async function mintTokens(address, amount){ if (await securityToken.methods.mintingFrozen().call()) { console.log(chalk.red("Minting is not possible - Minting has been permanently frozen by issuer")); } else { - let result = await securityToken.methods.getModulesByType(STO_KEY).call(); + let result = await securityToken.methods.getModulesByType(MODULES_TYPES.STO).call(); if (result.length > 0) { console.log(chalk.red("Minting is not possible - STO is attached to Security Token")); } else { @@ -466,16 +471,17 @@ async function isDividendsModuleAttached() { async function addDividendsModule() { if (!(await isDividendsModuleAttached())) { - let dividendsFactoryAddress; + let dividendsFactoryName; let dividendsModuleABI; if (dividendsType == 'POLY') { - dividendsFactoryAddress = await contracts.erc20DividendCheckpointFactoryAddress(); + dividendsFactoryName = 'ERC20DividendCheckpoint'; dividendsModuleABI = abis.erc20DividendCheckpoint(); } else if (dividendsType == 'ETH') { - dividendsFactoryAddress = await contracts.etherDividendCheckpointFactoryAddress(); + dividendsFactoryName = 'EtherDividendCheckpoint'; dividendsModuleABI = abis.etherDividendCheckpoint(); } + let dividendsFactoryAddress = await contracts.getModuleFactoryAddressByName(securityToken.options.address, MODULES_TYPES.DIVIDENDS, dividendsFactoryName); let addModuleAction = securityToken.methods.addModule(dividendsFactoryAddress, web3.utils.fromAscii('', 16), 0, 0); let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice); let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded'); diff --git a/CLI/commands/helpers/contract_abis.js b/CLI/commands/helpers/contract_abis.js index 116dbfd34..a505579d2 100644 --- a/CLI/commands/helpers/contract_abis.js +++ b/CLI/commands/helpers/contract_abis.js @@ -1,6 +1,7 @@ let polymathRegistryABI; let securityTokenRegistryABI; let featureRegistryABI; +let moduleRegistryABI; let securityTokenABI; let stoInterfaceABI; let cappedSTOABI; @@ -11,12 +12,14 @@ let cappedSTOFactoryABI; let usdTieredSTOFactoryABI; let erc20DividendCheckpointABI; let etherDividendCheckpointABI; -let ownable; +let ownableABI; +let moduleFactoryABI; try { polymathRegistryABI = JSON.parse(require('fs').readFileSync('./build/contracts/PolymathRegistry.json').toString()).abi; securityTokenRegistryABI = JSON.parse(require('fs').readFileSync('./build/contracts/SecurityTokenRegistry.json').toString()).abi; featureRegistryABI = JSON.parse(require('fs').readFileSync('./build/contracts/FeatureRegistry.json').toString()).abi; + moduleRegistryABI = JSON.parse(require('fs').readFileSync('./build/contracts/ModuleRegistry.json').toString()).abi; securityTokenABI = JSON.parse(require('fs').readFileSync('./build/contracts/SecurityToken.json').toString()).abi; stoInterfaceABI = JSON.parse(require('fs').readFileSync('./build/contracts/ISTO.json').toString()).abi; cappedSTOABI = JSON.parse(require('fs').readFileSync('./build/contracts/CappedSTO.json').toString()).abi; @@ -27,7 +30,8 @@ try { usdTieredSTOFactoryABI = JSON.parse(require('fs').readFileSync('./build/contracts/USDTieredSTOFactory.json').toString()).abi; erc20DividendCheckpointABI = JSON.parse(require('fs').readFileSync('./build/contracts/ERC20DividendCheckpoint.json').toString()).abi; etherDividendCheckpointABI = JSON.parse(require('fs').readFileSync('./build/contracts/EtherDividendCheckpoint.json').toString()).abi; - ownable = JSON.parse(require('fs').readFileSync('./build/contracts/Ownable.json').toString()).abi; + ownableABI = JSON.parse(require('fs').readFileSync('./build/contracts/Ownable.json').toString()).abi; + moduleFactoryABI = JSON.parse(require('fs').readFileSync('./build/contracts/ModuleFactory.json').toString()).abi; } catch (err) { console.log('\x1b[31m%s\x1b[0m',"Couldn't find contracts' artifacts. Make sure you ran truffle compile first"); return; @@ -43,6 +47,9 @@ module.exports = { featureRegistry: function () { return featureRegistryABI; }, + moduleRegistry: function () { + return moduleRegistryABI; + }, securityToken: function () { return securityTokenABI; }, @@ -74,6 +81,9 @@ module.exports = { return etherDividendCheckpointABI; }, ownable: function () { - return ownable; + return ownableABI; + }, + moduleFactory: function () { + return moduleFactoryABI; } } \ No newline at end of file diff --git a/CLI/commands/helpers/contract_addresses.js b/CLI/commands/helpers/contract_addresses.js index b4963e272..60c2531ea 100644 --- a/CLI/commands/helpers/contract_addresses.js +++ b/CLI/commands/helpers/contract_addresses.js @@ -39,7 +39,7 @@ async function getModuleRegistry() { if (typeof _moduleRegistry === 'undefined') { let polymathRegistry = await getPolymathRegistry(); let moduleRegistryAddress = await polymathRegistry.methods.getAddress("ModuleRegistry").call(); - let moduleRegistryAbi = abis.moduleRegistryAbi(); + let moduleRegistryAbi = abis.moduleRegistry(); _moduleRegistry = new web3.eth.Contract(moduleRegistryAbi, moduleRegistryAddress); _moduleRegistry.setProvider(web3.currentProvider); } @@ -77,45 +77,26 @@ module.exports = { else return JSON.parse(require('fs').readFileSync('./build/contracts/PolyTokenFaucet.json').toString()).networks[networkId].address; }, - cappedSTOFactoryAddress: async function() { - let networkId = await web3.eth.net.getId(); - if (networkId == 1) - return "0x2aa1b133f464ac08f66c2f702581d014e4603d31"; - else if (networkId == 42) - return "0x4527f1629b1d32ad8b900edebb766967c9c78715"; // Updated to 1.4.0 - else - return JSON.parse(require('fs').readFileSync('./build/contracts/CappedSTOFactory.json').toString()).networks[networkId].address; - }, - daiToken: async function() { - //TODO: Add a proper test DAI token here - let polymathRegistry = await getPolymathRegistry(); - return await polymathRegistry.methods.getAddress("PolyToken").call(); - }, - usdTieredSTOFactoryAddress: async function() { - let networkId = await web3.eth.net.getId(); - if (networkId == 1) - throw new Error("Not implemented"); - else if (networkId == 42) - return "0xcee7b602b6fc093c76f1bfcb05af6df7a9d39725"; // Updated to poly_oracle deployment - else - return JSON.parse(require('fs').readFileSync('./build/contracts/USDTieredSTOFactory.json').toString()).networks[networkId].address; - }, - etherDividendCheckpointFactoryAddress: async function() { - let networkId = await web3.eth.net.getId(); - if (networkId == 1) - return "0x0da7ed8789348ac40937cf6ae8ff521eee43816c"; - else if (networkId == 42) - return "0x870a07d45b0f4c5653fc29a4cb0697a01e0224b1"; - else - return JSON.parse(require('fs').readFileSync('./build/contracts/EtherDividendCheckpointFactory.json').toString()).networks[networkId].address; - }, - erc20DividendCheckpointFactoryAddress: async function() { - let networkId = await web3.eth.net.getId(); - if (networkId == 1) - return "0x6950096964b7adae34d5a3d1792fe73afbe9ddbc"; - else if (networkId == 42) - return "0x7e823f5df6ed1bb6cc005c692febc6aedf3b8889"; - else - return JSON.parse(require('fs').readFileSync('./build/contracts/ERC20DividendCheckpointFactory.json').toString()).networks[networkId].address; + getModuleFactoryAddressByName: async function(stAddress, moduleType, moduleName) { + let moduleRegistry = await getModuleRegistry(); + let availableModules = await moduleRegistry.methods.getAvailableModulesOfType(moduleType, stAddress).call(); + + let result = null; + let counter = 0; + let moduleFactoryABI = abis.moduleFactory(); + while (result == null && counter < availableModules.length) { + let moduleFactory = new web3.eth.Contract(moduleFactoryABI, availableModules[counter]); + let currentName = web3.utils.toAscii(await moduleFactory.methods.name().call()); + if (currentName.localeCompare(moduleName) == 0) { + result = moduleFactory.options.address; + } + counter++; + } + + if (result == null) { + throw new Error(`Module factory named ${moduleName} was not found.`); + } + + return result; } }; diff --git a/demo/checkpoint/ethExplorer.js b/demo/checkpoint/ethExplorer.js deleted file mode 100644 index a32bd6b18..000000000 --- a/demo/checkpoint/ethExplorer.js +++ /dev/null @@ -1,543 +0,0 @@ -const duration = { - seconds: function (val) { return val; }, - minutes: function (val) { return val * this.seconds(60); }, - hours: function (val) { return val * this.minutes(60); }, - days: function (val) { return val * this.hours(24); }, - weeks: function (val) { return val * this.days(7); }, - years: function (val) { return val * this.days(365); }, - }; -var readlineSync = require('readline-sync'); -var BigNumber = require('bignumber.js') -var chalk = require('chalk'); -var common = require('../common/common_functions'); - -var contracts = require("../helpers/contract_addresses"); -let tickerRegistryAddress = contracts.tickerRegistryAddress(); -let securityTokenRegistryAddress = contracts.securityTokenRegistryAddress(); -let cappedSTOFactoryAddress = contracts.cappedSTOFactoryAddress(); -let etherDividendCheckpointFactoryAddress = contracts.etherDividendCheckpointFactoryAddress(); - -let tickerRegistryABI; -let securityTokenRegistryABI; -let securityTokenABI; -let cappedSTOABI; -let generalTransferManagerABI; -try{ - tickerRegistryABI = JSON.parse(require('fs').readFileSync('./build/contracts/TickerRegistry.json').toString()).abi; - securityTokenRegistryABI = JSON.parse(require('fs').readFileSync('./build/contracts/SecurityTokenRegistry.json').toString()).abi; - securityTokenABI = JSON.parse(require('fs').readFileSync('./build/contracts/SecurityToken.json').toString()).abi; - cappedSTOABI = JSON.parse(require('fs').readFileSync('./build/contracts/CappedSTO.json').toString()).abi; - generalTransferManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/GeneralTransferManager.json').toString()).abi; - etherDividendCheckpointABI = JSON.parse(require('fs').readFileSync('./build/contracts/EtherDividendCheckpoint.json').toString()).abi; -}catch(err){ - console.log('\x1b[31m%s\x1b[0m',"Couldn't find contracts' artifacts. Make sure you ran truffle compile first"); - return; -} - - -const DEFAULT_GAS_PRICE = 80000000000; -const Web3 = require('web3'); - -if (typeof web3 !== 'undefined') { - web3 = new Web3(web3.currentProvider); -} else { - // set the provider you want from Web3.providers - web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); -} - -let tokenSymbol; -let securityToken; - -async function executeApp() { - - accounts = await web3.eth.getAccounts(); - Issuer = accounts[0]; - - setup(); - -}; - -async function setup(){ - try { - tickerRegistry = new web3.eth.Contract(tickerRegistryABI,tickerRegistryAddress); - tickerRegistry.setProvider(web3.currentProvider); - securityTokenRegistry = new web3.eth.Contract(securityTokenRegistryABI,securityTokenRegistryAddress); - securityTokenRegistry.setProvider(web3.currentProvider); - }catch(err){ - console.log(err) - console.log('\x1b[31m%s\x1b[0m',"There was a problem getting the contracts. Make sure they are deployed to the selected network."); - return; - } - - start_explorer(); - -} - -async function start_explorer(){ - - let tokenDeployed = false; - let tokenDeployedAddress; - if(!tokenSymbol){ - tokenSymbol = readlineSync.question('Enter the token symbol: '); - // Let's check if token has already been deployed, if it has, skip to STO - await securityTokenRegistry.methods.getSecurityTokenAddress(tokenSymbol).call({from: Issuer}, function(error, result){ - if(result != "0x0000000000000000000000000000000000000000"){ - securityToken = new web3.eth.Contract(securityTokenABI,result); - } - }); - } - - let checkpointNum = await securityToken.methods.currentCheckpointId().call({ from: Issuer }); - console.log("Token is at checkpoint:",checkpointNum); - - // Get the GTM - await securityToken.methods.getModule(2, 0).call({ from: Issuer }, function (error, result) { - generalTransferManagerAddress = result[1]; - }); - generalTransferManager = new web3.eth.Contract(generalTransferManagerABI, generalTransferManagerAddress); - generalTransferManager.setProvider(web3.currentProvider); - - await securityToken.methods.getModuleByName(4, web3.utils.toHex("EtherDividendCheckpoint")).call({ from: Issuer }, function (error, result) { - etherDividendCheckpointAddress = result[1]; - console.log("Dividends module address is:",etherDividendCheckpointAddress); - if(etherDividendCheckpointAddress != "0x0000000000000000000000000000000000000000"){ - etherDividendCheckpoint = new web3.eth.Contract(etherDividendCheckpointABI, etherDividendCheckpointAddress); - etherDividendCheckpoint.setProvider(web3.currentProvider); - } - }); - - let options = ['Mint tokens', 'Transfer tokens', 'Explore account at checkpoint', - 'Explore total supply at checkpoint', 'Create checkpoint', 'Issue Dividends', - 'Issue Dividends at a checkpoint', 'Tax Withholding', 'Push dividends to account', - 'Pull dividends to account', 'Explore ETH balance', 'Reclaimed dividends after expiry', 'Exit']; - let index = readlineSync.keyInSelect(options, 'What do you want to do?', {cancel: false}); - console.log("Selected:",options[index]); - switch(index){ - case 0: - let _to = readlineSync.question('Enter beneficiary of minting: '); - let _amount = readlineSync.question('Enter amount of tokens to mint: '); - await mintTokens(_to,_amount); - break; - case 1: - let _to2 = readlineSync.question('Enter beneficiary of tranfer: '); - let _amount2 = readlineSync.question('Enter amount of tokens to transfer: '); - await transferTokens(_to2,_amount2); - break; - case 2: - let _address = readlineSync.question('Enter address to explore: '); - let _checkpoint = readlineSync.question('At checkpoint: '); - await exploreAddress(_address,_checkpoint); - break; - case 3: - let _checkpoint2 = readlineSync.question('Explore total supply at checkpoint: '); - await exploreTotalSupply(_checkpoint2); - break; - case 4: - //Create new checkpoint - await securityToken.methods.createCheckpoint().send({ from: Issuer}); - break; - case 5: - //Create dividends - let ethDividend = readlineSync.question('How much eth would you like to distribute to token holders?: '); - await createDividends(ethDividend); - break; - case 6: - //Create dividends - let _ethDividend = readlineSync.question('How much eth would you like to distribute to token holders?: '); - let _checkpointId = readlineSync.question(`Enter the checkpoint on which you want to distribute dividend: `); - let currentCheckpointId = await securityToken.methods.currentCheckpointId().call(); - if (currentCheckpointId >= _checkpointId) { - await createDividendWithCheckpoint(_ethDividend, _checkpointId); - } else { - console.log(`Future checkpoint are not allowed to create the dividends`); - } - break; - case 7: - await withholdingTax(); - break; - case 8: - //Create dividends - let _checkpoint3 = readlineSync.question('Distribute dividends at checkpoint: '); - let _address2 = readlineSync.question('Enter address to push dividends to (ex- add1,add2,add3,...): '); - await pushDividends(_checkpoint3,_address2); - break; - case 9: - let _checkpoint7 = readlineSync.question('Distribute dividends at checkpoint: '); - await pullDividends(_checkpoint7); - break; - case 10: - //explore eth balance - let _checkpoint4 = readlineSync.question('Enter checkpoint to explore: '); - let _address3 = readlineSync.question('Enter address to explore: '); - let _dividendIndex = await etherDividendCheckpoint.methods.getDividendIndex(_checkpoint4).call(); - if (_dividendIndex.length == 1) { - let div = await etherDividendCheckpoint.methods.dividends(_dividendIndex[0]).call(); - let res = await etherDividendCheckpoint.methods.calculateDividend(_dividendIndex[0],_address3).call({ from: Issuer}); - let claim = new BigNumber(res[0]); - let withheld = new BigNumber(res[1]); - let percent = withheld.dividedBy(claim).times(100); - console.log(` - ETH Balance: ${web3.utils.fromWei((await web3.eth.getBalance(_address3)).toString(),"ether")} ETH - Dividend total size: ${web3.utils.fromWei((div.amount).toString(),"ether")} ETH - Dividends owed to investor at checkpoint ${_checkpoint4}: ${web3.utils.fromWei((claim).toString(),"ether")} ETH - Dividends withheld at checkpoint ${_checkpoint4}: ${web3.utils.fromWei((withheld).toString(),"ether")} ETH - Tax withholding percentage: ${percent}% - `) - } else { - console.log("Sorry Future checkpoints are not allowed"); - } - break; - case 11: - let _checkpoint5 = readlineSync.question('Enter the checkpoint to explore: '); - await reclaimedDividend(_checkpoint5); - break; - case 12: - process.exit(); - } - - //Restart - start_explorer(); - -} - -async function createDividends(ethDividend){ - // Get the Dividends module - await securityToken.methods.getModuleByName(4, web3.utils.toHex("EtherDividendCheckpoint")).call({ from: Issuer }, function (error, result) { - etherDividendCheckpointAddress = result[1]; - }); - if(etherDividendCheckpointAddress != "0x0000000000000000000000000000000000000000"){ - etherDividendCheckpoint = new web3.eth.Contract(etherDividendCheckpointABI, etherDividendCheckpointAddress); - etherDividendCheckpoint.setProvider(web3.currentProvider); - }else{ - let addModuleAction = securityToken.methods.addModule(etherDividendCheckpointFactoryAddress, web3.utils.fromAscii('', 16), 0, 0); - let GAS = await common.estimateGas(addModuleAction, Issuer, 1.2); - await addModuleAction.send({ from: Issuer, gas: GAS }) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! The transaction was successfully completed. - Module deployed at address: ${receipt.events.LogModuleAdded.returnValues._module} - Review it on Etherscan. - TxHash: ${receipt.transactionHash}\n` - ); - - etherDividendCheckpoint = new web3.eth.Contract(etherDividendCheckpointABI, receipt.events.LogModuleAdded.returnValues._module); - etherDividendCheckpoint.setProvider(web3.currentProvider); - }) - .on('error', console.error); - } - - let time = (await web3.eth.getBlock('latest')).timestamp; - let expiryTime = readlineSync.question('Enter the dividend expiry time (Unix Epoch time)\n(10 minutes from now = '+(time+duration.minutes(10))+' ): '); - let blacklist = readlineSync.question('Enter an address to blacklist from dividend distribution: '); - if(expiryTime == "") expiryTime = time+duration.minutes(10); - //Send eth dividends - let createDividendAction = etherDividendCheckpoint.methods.createDividend(time, expiryTime, [blacklist]); - GAS = await common.estimateGas(createDividendAction, Issuer, 1.2, web3.utils.toWei(ethDividend,"ether")); - await createDividendAction.send({ from: Issuer, value: web3.utils.toWei(ethDividend,"ether"), gas: GAS }) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - ${receipt.events} - TxHash: ${receipt.transactionHash}\n` - ); - }) -} - -async function withholdingTax() { - let GAS - let options = ['Set a % to withhold from the dividends sent to an address', 'Withdraw all withheld dividends', 'Return to main menu']; - let index = readlineSync.keyInSelect(options, 'What do you want to do?', {cancel: false}); - console.log("Selected:",options[index]); - switch (index) { - case 0: - let addressT = readlineSync.question('Enter the address of the investor for which to withhold dividends: '); - let percentT = readlineSync.question('Enter the percentage of dividends to withhold (number between 0-100): '); - percentT = web3.utils.toWei((percentT * 10).toString(), 'milli'); - GAS = Math.round(1.2 * (await etherDividendCheckpoint.methods.setWithholdingFixed([addressT], percentT).estimateGas({from: Issuer}))); - console.log(chalk.black.bgYellowBright(`---- Transaction executed: setWithholdingFixed - Gas limit provided: ${GAS} ----`)); - await etherDividendCheckpoint.methods.setWithholdingFixed([addressT], percentT).send({from: Issuer, gas: GAS, gasPrice: DEFAULT_GAS_PRICE }) - .on('receipt', function(receipt){ - console.log(chalk.green(`\nSuccessfully set tax withholding of ${web3.utils.fromWei(percentT, 'milli')/10}% for ${addressT}.`)); - }); - break; - case 1: - // Withdraw - let checkpointId = readlineSync.question('Enter the checkpoint at which to withdraw: '); - let dividendIndex = await etherDividendCheckpoint.methods.getDividendIndex(checkpointId).call(); - if (dividendIndex.length == 1) { - GAS = Math.round(1.2 * (await etherDividendCheckpoint.methods.withdrawWithholding(dividendIndex[0]).estimateGas({from: Issuer}))); - console.log(chalk.black.bgYellowBright(`---- Transaction executed: withdrawWithholding - Gas limit provided: ${GAS} ----`)); - await etherDividendCheckpoint.methods.withdrawWithholding(dividendIndex[0]).send({from: Issuer, gas: GAS, gasPrice: DEFAULT_GAS_PRICE }) - .on('receipt', function(receipt){ - let val = receipt.events.EtherDividendWithholdingWithdrawn.returnValues._withheldAmount; - console.log(chalk.green(`\nSuccessfully withdrew ${val} ETH from checkpoint ${checkpointId} and dividend ${dividendIndex[0]} tax withholding to ${Issuer}.`)); - }); - }else{ - console.log(`\nCheckpoint doesn't exist`); - } - break; - case 2: - return; - break; - } -} - -async function createDividendWithCheckpoint(ethDividend, _checkpointId) { - - // Get the Dividends module - await securityToken.methods.getModuleByName(4, web3.utils.toHex("EtherDividendCheckpoint")).call({ from: Issuer }, function (error, result) { - etherDividendCheckpointAddress = result[1]; - }); - if(etherDividendCheckpointAddress != "0x0000000000000000000000000000000000000000"){ - etherDividendCheckpoint = new web3.eth.Contract(etherDividendCheckpointABI, etherDividendCheckpointAddress); - etherDividendCheckpoint.setProvider(web3.currentProvider); - }else{ - let addModuleAction = securityToken.methods.addModule(etherDividendCheckpointFactoryAddress, web3.utils.fromAscii('', 16), 0, 0); - let GAS = await common.estimateGas(addModuleAction, Issuer, 1.2); - await addModuleAction.send({ from: Issuer, gas: GAS }) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! The transaction was successfully completed. - Module deployed at address: ${receipt.events.LogModuleAdded.returnValues._module} - Review it on Etherscan. - TxHash: ${receipt.transactionHash}\n` - ); - - etherDividendCheckpoint = new web3.eth.Contract(etherDividendCheckpointABI, receipt.events.LogModuleAdded.returnValues._module); - etherDividendCheckpoint.setProvider(web3.currentProvider); - }) - .on('error', console.error); - } - - let time = (await web3.eth.getBlock('latest')).timestamp; - let expiryTime = readlineSync.question('Enter the dividend expiry time (Unix Epoch time)\n(10 minutes from now = '+(time+duration.minutes(10))+' ): '); - if(expiryTime == "") expiryTime = time+duration.minutes(10); - let _dividendStatus = await etherDividendCheckpoint.methods.getDividendIndex(_checkpointId).call(); - if (_dividendStatus.length != 1) { - //Send eth dividends - let createDividendWithCheckpointAction = etherDividendCheckpoint.methods.createDividendWithCheckpoint(time, expiryTime, _checkpointId, []); - let GAS = await common.estimateGas(createDividendWithCheckpointAction, Issuer, 1.2, web3.utils.toWei(ethDividend,"ether")); - await createDividendWithCheckpointAction.send({ from: Issuer, value: web3.utils.toWei(ethDividend,"ether"), gas: GAS }) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! Dividend is created successfully. - CheckpointId: ${receipt.events.EtherDividendDeposited.returnValues._checkpointId} - TxHash: ${receipt.transactionHash}\n` - ); - }) - .on('error', console.error); - } else { - console.log(chalk.blue(`\nDividends are already distributed at checkpoint '${_checkpointId}'. Not allowed to re-create\n`)); - } -} - -async function pushDividends(checkpoint, account){ - let accs = account.split(','); - let dividend = await etherDividendCheckpoint.methods.getDividendIndex(checkpoint).call(); - if(dividend.length == 1) { - let pushDividendPaymentToAddressesAction = etherDividendCheckpoint.methods.pushDividendPaymentToAddresses(dividend[0], accs); - let GAS = await common.estimateGas(pushDividendPaymentToAddressesAction, Issuer, 1.2); - await pushDividendPaymentToAddressesAction.send({ from: Issuer, gas: GAS }) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! Dividends are pushed successfully - TxHash: ${receipt.transactionHash}\n` - ); - }) - } else { - console.log(`Checkpoint is not yet created. Please enter the pre-created checkpoint`); - } - - -} - -async function pullDividends(checkpointId) { - let dividend = await etherDividendCheckpoint.methods.getDividendIndex(checkpointId).call(); - if(dividend.length == 1) { - try { - let pullDividendPaymentAction = etherDividendCheckpoint.methods.pullDividendPayment(dividend[0]); - let GAS = await common.estimateGas(pullDividendPaymentAction, Issuer, 1.2); - await pullDividendPaymentAction.send({ from: Issuer, gas: GAS }) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Amount: ${web3.utils.fromWei(receipt.events.EtherDividendClaimed.returnValues._amount, "ether")} ETH - Payee: ${receipt.events.EtherDividendClaimed.returnValues._payee} - TxHash: ${receipt.transactionHash}\n` - ); - }) - .on('error', console.error); - } catch(error) { - console.log(error.message); - } - } else { - console.log(`Checkpoint is not yet created. Please enter the pre-created checkpoint`); - } -} - -async function exploreAddress(address, checkpoint){ - let balance = await securityToken.methods.balanceOf(address).call({from: Issuer}); - balance = web3.utils.fromWei(balance,"ether"); - console.log("Balance of",address,"is:",balance,"(Using balanceOf)"); - - let balanceAt = await securityToken.methods.balanceOfAt(address,checkpoint).call({from: Issuer}); - balanceAt = web3.utils.fromWei(balanceAt,"ether"); - console.log("Balance of",address,"is:",balanceAt,"(Using balanceOfAt - checkpoint",checkpoint,")"); -} - -async function exploreTotalSupply(checkpoint){ - let totalSupply = await securityToken.methods.totalSupply().call({from: Issuer}); - totalSupply = web3.utils.fromWei(totalSupply,"ether"); - console.log("TotalSupply is:",totalSupply,"(Using totalSupply)"); - - let totalSupplyAt = await securityToken.methods.totalSupplyAt(checkpoint).call({from: Issuer}); - totalSupplyAt = web3.utils.fromWei(totalSupplyAt,"ether"); - console.log("totalSupply is:",totalSupplyAt,"(Using totalSupplyAt - checkpoint",checkpoint,")"); -} - - -async function transferTokens(address, amount){ - - let modifyWhitelistAction = generalTransferManager.methods.modifyWhitelist(address, Math.floor(Date.now()/1000), Math.floor(Date.now()/1000), Math.floor(Date.now()/1000 + 31536000), true); - let GAS = await common.estimateGas(modifyWhitelistAction, Issuer, 1.2); - let whitelistTransaction = await modifyWhitelistAction.send({ from: Issuer, gas: GAS}); - - try{ - let transferAction = securityToken.methods.transfer(address,web3.utils.toWei(amount,"ether")); - GAS = await common.estimateGas(transferAction, Issuer, 1.2); - await transferAction.send({ from: Issuer, gas: GAS}) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! The transaction was successfully completed. - - Account ${receipt.events.Transfer.returnValues.from} - transfered ${web3.utils.fromWei(receipt.events.Transfer.returnValues.value,"ether")} tokens - to account ${receipt.events.Transfer.returnValues.to} - - Review it on Etherscan. - TxHash: ${receipt.transactionHash}\n` - ); - }); - - }catch (err){ - console.log(err); - console.log("There was an error processing the transfer transaction. \n The most probable cause for this error is one of the involved accounts not being in the whitelist or under a lockup period.") - return; - } -} - -async function mintTokens(address, amount){ - let isSTOAttached; - let modifyWhitelistAction = generalTransferManager.methods.modifyWhitelist(address,Math.floor(Date.now()/1000),Math.floor(Date.now()/1000),Math.floor(Date.now()/1000 + 31536000),true); - let GAS = await common.estimateGas(modifyWhitelistAction, Issuer, 1.2); - let whitelistTransaction = await modifyWhitelistAction.send({ from: Issuer, gas: GAS}); - let _flag = await securityToken.methods.finishedIssuerMinting().call(); - await securityToken.methods.getModule(3, 0).call({from: Issuer}, function(error, result) { - isSTOAttached = result[1] == "0x0000000000000000000000000000000000000000"? false : true; - }); - if (isSTOAttached || _flag) { - console.log("\n"); - console.log("***************************") - console.log("Minting is Finished"); - console.log("***************************\n") - return; - } - try{ - let mintAction = securityToken.methods.mint(address,web3.utils.toWei(amount,"ether")); - GAS = await common.estimateGas(mintAction, Issuer, 1.2); - await mintAction.send({ from: Issuer, gas: GAS}) - .on('transactionHash', function(hash){ - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! The transaction was successfully completed. - - Minted ${web3.utils.fromWei(receipt.events.Transfer.returnValues.value,"ether")} tokens - to account ${receipt.events.Transfer.returnValues.to} - - Review it on Etherscan. - TxHash: ${receipt.transactionHash}\n` - ); - }); - - }catch (err){ - console.log(err); - console.log("There was an error processing the transfer transaction. \n The most probable cause for this error is one of the involved accounts not being in the whitelist or under a lockup period.") - return; - } -} - -async function reclaimedDividend(checkpointId) { - let dividendIndex = await etherDividendCheckpoint.methods.getDividendIndex(checkpointId).call(); - if (dividendIndex.length == 1) { - let reclaimDividendAction = etherDividendCheckpoint.methods.reclaimDividend(dividendIndex[0]); - let GAS = await common.estimateGas(reclaimDividendAction, Issuer, 1.2); - await reclaimDividendAction.send({from: Issuer, gas: GAS}) - .on("transactionHash", function(hash) { - console.log(` - Your transaction is being processed. Please wait... - TxHash: ${hash}\n` - ); - }) - .on('receipt', function(receipt){ - console.log(` - Congratulations! The transaction was successfully completed. - - Claimed Amount ${web3.utils.fromWei(receipt.events.EtherDividendReclaimed.returnValues._claimedAmount,"ether")} ETH - to account ${receipt.events.EtherDividendReclaimed.returnValues._claimer} - - Review it on Etherscan. - TxHash: ${receipt.transactionHash}\n` - ); - }) - .on('error', console.error); - }else{ - console.log(`\nCheckpoint doesn't exist`); - } -} - -executeApp(); From 4da0183b0ca1f6167e33d6e97446399f0df79255 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Fri, 28 Sep 2018 16:20:40 -0300 Subject: [PATCH 17/63] Get checkpoints from function istead of events --- CLI/commands/dividends_manager.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index 5222cb167..aeb81d818 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -506,18 +506,12 @@ async function selectCheckpoint(includeCreate) { async function getCheckpoints() { let result = []; - /* - let currentCheckpoint = await securityToken.methods.currentCheckpointId().call(); - for (let index = 1; index <= currentCheckpoint; index++) { - result.push(checkpoint(index).call()); - } - */ - - let events = await securityToken.getPastEvents('CheckpointCreated', { fromBlock: 0}); - for (let event of events) { + + let checkPointsTimestamps = await securityToken.methods.getCheckpointTimes().call(); + for (let index = 0; index < checkPointsTimestamps.length; index++) { let checkpoint = {}; - checkpoint.id = event.returnValues._checkpointId; - checkpoint.timestamp = moment.unix(event.returnValues._timestamp).format('MMMM Do YYYY, HH:mm:ss'); + checkpoint.id = index + 1; + checkpoint.timestamp = moment.unix(checkPointsTimestamps[index]).format('MMMM Do YYYY, HH:mm:ss'); result.push(checkpoint); } From e94e0255f0194ebc9f1c0ba10bbae530b3f8dd2a Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 30 Sep 2018 18:58:09 +0100 Subject: [PATCH 18/63] WIP --- contracts/SecurityTokenRegistry.sol | 21 ++++++++++----------- test/n_security_token_registry.js | 7 +++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 9ec100df1..882a58ba4 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -78,8 +78,6 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // Emit when ownership of the ticker gets changed event ChangeTickerOwnership(string _ticker, address indexed _oldOwner, address indexed _newOwner); - // Emit when a ticker details is modified - event ModifyTickerDetails(address _owner, string _ticker, string _name, uint256 _registrationDate, uint256 _expiryDate, bool _status); // Emit at the time of launching a new security token event NewSecurityToken( string _ticker, @@ -622,15 +620,16 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _minor Minor version of the proxy. * @param _patch Patch version of the proxy */ - function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) public onlyOwner { - uint8[] memory _version = new uint8[](3); - _version[0] = _major; - _version[1] = _minor; - _version[2] = _patch; - uint24 _packedVersion = VersionUtils.pack(_major, _minor, _patch); - require(VersionUtils.isValidVersion(getProtocolVersion(), _version),"Invalid version"); - set(Encoder.getKey("latestVersion"), uint256(_packedVersion)); - set(Encoder.getKey("protocolVersionST", uint256(_packedVersion)), _STFactoryAddress); + function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) public { + uint8[] memory version = new uint8[](3); + version[0] = _major; + version[1] = _minor; + version[2] = _patch; + uint24 packedVersion = VersionUtils.pack(_major, _minor, _patch); + require(VersionUtils.isValidVersion(getProtocolVersion(), version),"Invalid version"); + set(Encoder.getKey("latestVersion"), uint256(packedVersion)); + set(Encoder.getKey("protocolVersionST", getUint(Encoder.getKey("latestVersion"))), _STFactoryAddress); + /* set(Encoder.getKey("protocolVersionST", uint256(_packedVersion)), _STFactoryAddress); */ } /** diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index a53378c8b..d9e3cdf98 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -131,7 +131,7 @@ contract('SecurityTokenRegistry', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -203,7 +203,7 @@ contract('SecurityTokenRegistry', accounts => { "SecurityTokenRegistry contract was not deployed", ); - // Step 9 (a): Deploy the proxy + // Step 9 (a): Deploy the proxy I_SecurityTokenRegistryProxy = await SecurityTokenRegistryProxy.new({from: account_polymath}); let bytesProxy = encodeProxyCall(STRProxyParameters, [I_PolymathRegistry.address, I_STFactory.address, initRegFee, initRegFee, I_PolyToken.address, account_polymath]); await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); @@ -833,8 +833,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should change the details of the existing ticker", async() => { let tx = await I_STRProxied.modifyTicker(token_owner, "ETH", "Ether", latestTime(), (latestTime() + duration.minutes(10)), false, {from: account_polymath}); - assert.equal(tx.logs[0].args._oldOwner, account_temp); - assert.equal(tx.logs[0].args._newOwner, token_owner); + assert.equal(tx.logs[0].args._owner, token_owner); }); }); From cd952c3a9119556101755ce4bb105f62436c3c50 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 30 Sep 2018 19:43:10 +0100 Subject: [PATCH 19/63] Updates --- contracts/SecurityTokenRegistry.sol | 37 ++++++++++++++++++++++------- test/n_security_token_registry.js | 9 ++++++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 882a58ba4..c8174e258 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -183,13 +183,13 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_owner != address(0), "Owner should not be 0x"); require(bytes(_ticker).length > 0 && bytes(_ticker).length <= 10, "Ticker length range (0,10]"); // Attempt to charge the reg fee if it is > 0 POLY - uint256 tickerFee = getUint(Encoder.getKey("tickerRegFee")); + uint256 tickerFee = getTickerRegistrationFee(); if (tickerFee > 0) require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), tickerFee), "Insufficent allowance"); string memory ticker = Util.upper(_ticker); require(_tickerAvailable(ticker), "Ticker is reserved"); // Check whether ticker was previously registered (and expired) - address previousOwner = getAddress(Encoder.getKey("registeredTickers_owner", ticker)); + address previousOwner = _tickerOwner(ticker); if (previousOwner != address(0)) { _deleteTickerOwnership(previousOwner, ticker); } @@ -228,7 +228,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Internal -- Modifies the ticker details. */ function _modifyTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status) internal { - address currentOwner = getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); + address currentOwner = _tickerOwner(_ticker); if (currentOwner != address(0)) { _deleteTickerOwnership(currentOwner, _ticker); } @@ -238,13 +238,17 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { _addTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _status, true); } + function _tickerOwner(string _ticker) internal view returns(address) { + return getAddress(Encoder.getKey("registeredTickers_owner", _ticker)); + } + /** * @notice Removes the ticker details, associated ownership & security token mapping * @param _ticker is the token ticker */ function removeTicker(string _ticker) external onlyOwner { string memory ticker = Util.upper(_ticker); - address owner = getAddress(Encoder.getKey("registeredTickers_owner", ticker)); + address owner = _tickerOwner(ticker); require(owner != address(0), "Ticker doesn't exist"); _deleteTickerOwnership(owner, ticker); set(Encoder.getKey("tickerToSecurityToken", ticker), address(0)); @@ -258,7 +262,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @return bool */ function _tickerAvailable(string _ticker) internal view returns(bool) { - if (getAddress(Encoder.getKey("registeredTickers_owner", _ticker)) != address(0)) { + if (_tickerOwner(_ticker) != address(0)) { if ((now > getUint(Encoder.getKey("registeredTickers_expiryDate", _ticker))) && !_tickerStatus(_ticker)) { return true; } else @@ -320,9 +324,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(getAddress(ownerKey) == msg.sender, "Not authorised"); if (_tickerStatus(ticker)) require(IOwnable(getAddress(Encoder.getKey("tickerToSecurityToken", ticker))).owner() == _newOwner, "New owner does not match token owner"); - set(ownerKey, _newOwner); _deleteTickerOwnership(msg.sender, ticker); _setTickerOwnership(_newOwner, ticker); + set(ownerKey, _newOwner); emit ChangeTickerOwnership(ticker, msg.sender, _newOwner); } @@ -429,7 +433,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if ((tickerStatus == true) || (expiryDate > now)) { return ( - getAddress(Encoder.getKey("registeredTickers_owner", ticker)), + _tickerOwner(ticker), getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), expiryDate, getString(Encoder.getKey("registeredTickers_tokenName", ticker)), @@ -456,10 +460,10 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { bytes32 statusKey = Encoder.getKey("registeredTickers_status", ticker); require(getBool(statusKey) != true, "Already deployed"); set(statusKey, true); - require(getAddress(Encoder.getKey("registeredTickers_owner", ticker)) == msg.sender, "Not authorised"); + require(_tickerOwner(ticker) == msg.sender, "Not authorised"); require(getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker gets expired"); - uint256 launchFee = getUint(Encoder.getKey("stLaunchFee")); + uint256 launchFee = getSecurityTokenLaunchFee(); if (launchFee > 0) require(IERC20(getAddress(Encoder.getKey("polyToken"))).transferFrom(msg.sender, address(this), launchFee), "Insufficient allowance"); @@ -655,5 +659,20 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { set(Encoder.getKey("polyToken"), _newAddress); } + /** + * @notice Gets the security token launch fee + * @return Fee amount + */ + function getSecurityTokenLaunchFee() public view returns(uint256) { + return getUint(Encoder.getKey("stLaunchFee")); + } + + /** + * @notice Gets the ticker registration fee + * @return Fee amount + */ + function getTickerRegistrationFee() public view returns(uint256) { + return getUint(Encoder.getKey("tickerRegFee")); + } } diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index d9e3cdf98..a729f2d37 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -739,9 +739,15 @@ contract('SecurityTokenRegistry', accounts => { // Register the new ticker -- Fulfiling the TickerStatus.ON condition await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: account_temp}); + let tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); + console.log(tickersListArray); await I_STRProxied.registerTicker(account_temp, "LOG", "LOGAN", { from : account_temp }); + tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); + console.log(tickersListArray); // Generating the ST let tx = await I_STRProxied.modifySecurityToken("LOGAN", "LOG", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); + tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); + console.log(tickersListArray); assert.equal(tx.logs[1].args._ticker, "LOG", "Symbol should match with the registered symbol"); assert.equal(tx.logs[1].args._securityTokenAddress, dummy_token,`Address of the SecurityToken should be matched with the input value of addCustomSecurityToken`); let symbolDetails = await I_STRProxied.getTickerDetails("LOG"); @@ -1082,7 +1088,8 @@ contract('SecurityTokenRegistry', accounts => { let tickersList = await I_STRProxied.getTickersByOwner.call(token_owner); assert.equal(tickersList.length, 4); let tickersListArray = await I_STRProxied.getTickersByOwner.call(account_temp); - assert.equal(tickersListArray.length, 2); + console.log(tickersListArray); + assert.equal(tickersListArray.length, 3); }); }); From e425691a342856994561d4bf4c97a7585cad004b Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 30 Sep 2018 20:23:06 +0100 Subject: [PATCH 20/63] Add assertion --- contracts/SecurityTokenRegistry.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index c8174e258..d6fb7b562 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -338,6 +338,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { bytes32 ownerKey = Encoder.getKey("userToTickers", _owner); bytes32[] memory tickers = getArrayBytes32(ownerKey); assert(index < tickers.length); + assert(_tickerOwner(_ticker) == _owner); deleteArrayBytes32(Encoder.getKey("userToTickers", _owner), index); if (tickers.length > index) { bytes32 switchedTicker = tickers[index]; From 7ad0c19375cccdff960729205d45873c12610e0a Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 30 Sep 2018 20:26:29 +0100 Subject: [PATCH 21/63] Update interface --- contracts/SecurityTokenRegistry.sol | 10 +++++++++- .../interfaces/ISecurityTokenRegistry.sol | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index d6fb7b562..671cd5c82 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -193,7 +193,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if (previousOwner != address(0)) { _deleteTickerOwnership(previousOwner, ticker); } - _addTicker(_owner, ticker, _tokenName, now, now.add(getUint(Encoder.getKey("expiryLimit"))), false, false); + _addTicker(_owner, ticker, _tokenName, now, now.add(getExpiryLimit()), false, false); } /** @@ -676,4 +676,12 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return getUint(Encoder.getKey("tickerRegFee")); } + /** + * @notice Gets the expiry limit + * @return Expiry limit + */ + function getExpiryLimit() public view returns(uint256) { + return getUint(Encoder.getKey("expiryLimit")); + } + } diff --git a/contracts/interfaces/ISecurityTokenRegistry.sol b/contracts/interfaces/ISecurityTokenRegistry.sol index d7ec8f9f0..87c02cc90 100644 --- a/contracts/interfaces/ISecurityTokenRegistry.sol +++ b/contracts/interfaces/ISecurityTokenRegistry.sol @@ -159,4 +159,22 @@ interface ISecurityTokenRegistry { */ function updatePolyTokenAddress(address _newAddress) external; + /** + * @notice Gets the security token launch fee + * @return Fee amount + */ + function getSecurityTokenLaunchFee() external view returns(uint256); + + /** + * @notice Gets the ticker registration fee + * @return Fee amount + */ + function getTickerRegistrationFee() external view returns(uint256); + + /** + * @notice Gets the expiry limit + * @return Expiry limit + */ + function getExpiryLimit() external view returns(uint256); + } From 0384c3c4a6eaad8402c65541cedbdb3f4aace033 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Sun, 30 Sep 2018 23:52:18 +0100 Subject: [PATCH 22/63] Update tests --- contracts/libraries/KindMath.sol | 53 ++++++++++ contracts/tokens/SecurityToken.sol | 4 +- test/o_security_token.js | 152 +++++++++++++---------------- 3 files changed, 123 insertions(+), 86 deletions(-) create mode 100644 contracts/libraries/KindMath.sol diff --git a/contracts/libraries/KindMath.sol b/contracts/libraries/KindMath.sol new file mode 100644 index 000000000..92d77362e --- /dev/null +++ b/contracts/libraries/KindMath.sol @@ -0,0 +1,53 @@ +pragma solidity ^0.4.24; + +// Copied from OpenZeppelin and modified to be friendlier + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library KindMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { + // Gas optimization: this is cheaper than requireing 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 + if (a == 0) { + return 0; + } + + c = a * b; + require(c / a == b, "mul overflow"); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + // require(b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = a / b; + // require(a == b * c + a % b); // There is no case in which this doesn't hold + return a / b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "sub overflow"); + return a - b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a + b; + require(c >= a, "add overflow"); + return c; + } +} diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 7a62360a0..e83724ecb 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -136,7 +136,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr // Events to log controller actions event SetController(address indexed _oldController, address indexed _newController); event ForceTransfer(address indexed _controller, address indexed _from, address indexed _to, uint256 _value, bool _verifyTransfer, bytes _data); - event ForceBurn(address indexed _controller, address indexed _from, uint256 _value, bytes _data); + event ForceBurn(address indexed _controller, address indexed _from, uint256 _value, bool _verifyTransfer, bytes _data); event DisableController(uint256 _timestamp); function isModule(address _module, uint8 _type) internal view returns (bool) { @@ -823,7 +823,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr bool verified = _updateTransfer(_from, address(0), _value); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); - emit ForceBurn(msg.sender, _from, _value, _data); + emit ForceBurn(msg.sender, _from, _value, verified, _data); emit Burnt(_from, _value); emit Transfer(_from, address(0), _value); return true; diff --git a/test/o_security_token.js b/test/o_security_token.js index 8e4223f7d..f1a905154 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -139,7 +139,7 @@ contract('SecurityToken', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -1106,36 +1106,6 @@ contract('SecurityToken', accounts => { await I_SecurityToken.transfer(account_investor1, web3.utils.toWei('1', 'ether'), {from: account_temp}); }); - it("Should fail to call the burn the tokens because token burner contract is not set", async() => { - let errorThrown = false; - try { - await I_SecurityToken.burn(web3.utils.toWei('1', 'ether'),{ from: account_temp }); - } catch(error) { - console.log(' tx revert -> Token burner contract is not set'.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - }); - - it("Should fail to call the burn the tokens because TM does not allow it", async ()=> { - // Deploy the token burner contract - I_TokenBurner = await TokenBurner.new(I_SecurityToken.address, { from: token_owner }); - - await I_SecurityToken.setTokenBurner(I_TokenBurner.address, { from: token_owner }); - assert.equal(await I_SecurityToken.tokenBurner.call(), I_TokenBurner.address); - let errorThrown = false; - try { - await I_SecurityToken.burn(web3.utils.toWei('1', 'ether'),{ from: account_temp }); - } catch(error) { - console.log(' tx revert -> Token burner contract is not set'.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - - }); - it("Should check that the list of investors is correct", async ()=> { // Hardcode list of expected accounts based on transfers above let investorsLength = await I_SecurityToken.getInvestorsLength(); @@ -1148,27 +1118,76 @@ contract('SecurityToken', accounts => { assert.equal(investor, expectedAccounts[i]); } }); + it("Should fail to set controller status because msg.sender not owner", async() => { + let errorThrown = false; + try { + await I_SecurityToken.setController(account_controller, {from: account_controller}); + } catch (error) { + console.log(` tx revert -> msg.sender not owner`.grey); + errorThrown = true; + ensureException(error); + } + assert.ok(errorThrown, message); + }); - it("Should burn the tokens", async ()=> { - let errorThrown = false; - await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, {from : token_owner}); - let currentInvestorCount = await I_SecurityToken.investorCount(); - let currentBalance = await I_SecurityToken.balanceOf(account_temp); - try { - let tx = await I_SecurityToken.burn(currentBalance + web3.utils.toWei("500", "ether"), { from: account_temp }); - } catch(error) { - console.log(` tx revert -> value is greater than its current balance`.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - }); + it("Should successfully set controller", async() => { + let tx1 = await I_SecurityToken.setController(account_controller, {from: token_owner}); + + // check event + assert.equal(address_zero, tx1.logs[0].args._oldController, "Event not emitted as expected"); + assert.equal(account_controller, tx1.logs[0].args._newController, "Event not emitted as expected"); + + let tx2 = await I_SecurityToken.setController(address_zero, {from: token_owner}); + + // check event + assert.equal(account_controller, tx2.logs[0].args._oldController, "Event not emitted as expected"); + assert.equal(address_zero, tx2.logs[0].args._newController, "Event not emitted as expected"); + + let tx3 = await I_SecurityToken.setController(account_controller, {from: token_owner}); + + // check event + assert.equal(address_zero, tx3.logs[0].args._oldController, "Event not emitted as expected"); + assert.equal(account_controller, tx3.logs[0].args._newController, "Event not emitted as expected"); + + // check status + let controller = await I_SecurityToken.controller.call(); + assert.equal(account_controller, controller, "Status not set correctly"); + }); + + it("Should force burn the tokens - value too high", async ()=> { + let errorThrown = false; + await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, {from : token_owner}); + let currentInvestorCount = await I_SecurityToken.investorCount(); + let currentBalance = await I_SecurityToken.balanceOf(account_temp); + try { + let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance + web3.utils.toWei("500", "ether"), "", { from: account_controller }); + } catch(error) { + console.log(` tx revert -> value is greater than its current balance`.grey); + errorThrown = true; + ensureException(error); + } + assert.ok(errorThrown, message); + }); + it("Should force burn the tokens - wrong caller", async ()=> { + let errorThrown = false; + await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, {from : token_owner}); + let currentInvestorCount = await I_SecurityToken.investorCount(); + let currentBalance = await I_SecurityToken.balanceOf(account_temp); + try { + let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", { from: token_owner }); + } catch(error) { + console.log(` tx revert -> not owner`.grey); + errorThrown = true; + ensureException(error); + } + assert.ok(errorThrown, message); + }); it("Should burn the tokens", async ()=> { let currentInvestorCount = await I_SecurityToken.investorCount(); let currentBalance = await I_SecurityToken.balanceOf(account_temp); // console.log(currentInvestorCount.toString(), currentBalance.toString()); - let tx = await I_SecurityToken.burn(currentBalance, { from: account_temp }); + let tx = await I_SecurityToken.forceBurn(account_temp, currentBalance, "", { from: account_controller }); // console.log(tx.logs[0].args._value.toNumber(), currentBalance.toNumber()); assert.equal(tx.logs[0].args._value.toNumber(), currentBalance.toNumber()); let newInvestorCount = await I_SecurityToken.investorCount(); @@ -1243,42 +1262,6 @@ contract('SecurityToken', accounts => { describe("Force Transfer", async() => { - it("Should fail to set controller status because msg.sender not owner", async() => { - let errorThrown = false; - try { - await I_SecurityToken.setController(account_controller, {from: account_controller}); - } catch (error) { - console.log(` tx revert -> msg.sender not owner`.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - }); - - it("Should successfully set controller", async() => { - let tx1 = await I_SecurityToken.setController(account_controller, {from: token_owner}); - - // check event - assert.equal(address_zero, tx1.logs[0].args._oldController, "Event not emitted as expected"); - assert.equal(account_controller, tx1.logs[0].args._newController, "Event not emitted as expected"); - - let tx2 = await I_SecurityToken.setController(address_zero, {from: token_owner}); - - // check event - assert.equal(account_controller, tx2.logs[0].args._oldController, "Event not emitted as expected"); - assert.equal(address_zero, tx2.logs[0].args._newController, "Event not emitted as expected"); - - let tx3 = await I_SecurityToken.setController(account_controller, {from: token_owner}); - - // check event - assert.equal(address_zero, tx3.logs[0].args._oldController, "Event not emitted as expected"); - assert.equal(account_controller, tx3.logs[0].args._newController, "Event not emitted as expected"); - - // check status - let controller = await I_SecurityToken.controller.call(); - assert.equal(account_controller, controller, "Status not set correctly"); - }); - it("Should fail to forceTransfer because not approved controller", async() => { let errorThrown1 = false; try { @@ -1332,11 +1315,12 @@ contract('SecurityToken', accounts => { assert.equal(start_investorCount.add(1).toNumber(), end_investorCount.toNumber(), "Investor count not changed"); assert.equal(start_balInv1.sub(web3.utils.toWei("10", "ether")).toNumber(), end_balInv1.toNumber(), "Investor balance not changed"); assert.equal(start_balInv2.add(web3.utils.toWei("10", "ether")).toNumber(), end_balInv2.toNumber(), "Investor balance not changed"); - + console.log(tx.logs[0].args); + console.log(tx.logs[1].args); assert.equal(account_controller, tx.logs[0].args._controller, "Event not emitted as expected"); assert.equal(account_investor1, tx.logs[0].args._from, "Event not emitted as expected"); assert.equal(account_investor2, tx.logs[0].args._to, "Event not emitted as expected"); - assert.equal(web3.utils.toWei("10", "ether"), tx.logs[0].args._amount, "Event not emitted as expected"); + assert.equal(web3.utils.toWei("10", "ether"), tx.logs[0].args._value, "Event not emitted as expected"); console.log(tx.logs[0].args._verifyTransfer); assert.equal(false, tx.logs[0].args._verifyTransfer, "Event not emitted as expected"); assert.equal("reason", web3.utils.hexToUtf8(tx.logs[0].args._data), "Event not emitted as expected"); From 9d547ec67b6f5a6c9a3a48608898f875b915652f Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 00:07:00 +0100 Subject: [PATCH 23/63] Add module test cases --- test/v_tracked_redemptions.js | 378 ++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 test/v_tracked_redemptions.js diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js new file mode 100644 index 000000000..0f767214f --- /dev/null +++ b/test/v_tracked_redemptions.js @@ -0,0 +1,378 @@ +import latestTime from './helpers/latestTime'; +import { duration, ensureException, promisifyLogWatch, latestBlock } from './helpers/utils'; +import takeSnapshot, { increaseTime, revertToSnapshot } from './helpers/time'; +import { encodeProxyCall } from './helpers/encodeCall'; + +const PolymathRegistry = artifacts.require('./PolymathRegistry.sol') +const ModuleRegistry = artifacts.require('./ModuleRegistry.sol'); +const ModuleRegistryProxy = artifacts.require('./ModuleRegistryProxy.sol'); +const SecurityToken = artifacts.require('./SecurityToken.sol'); +const SecurityTokenRegistry = artifacts.require('./SecurityTokenRegistry.sol'); +const SecurityTokenRegistryProxy = artifacts.require('./SecurityTokenRegistryProxy.sol'); +const FeatureRegistry = artifacts.require('./FeatureRegistry.sol'); +const STFactory = artifacts.require('./STFactory.sol'); +const GeneralPermissionManagerFactory = artifacts.require('./GeneralPermissionManagerFactory.sol'); +const GeneralTransferManagerFactory = artifacts.require('./GeneralTransferManagerFactory.sol'); +const GeneralTransferManager = artifacts.require('./GeneralTransferManager'); +const TrackedRedemptionFactory = artifacts.require('./TrackedRedemptionFactory.sol'); +const TrackedRedemption = artifacts.require('./TrackedRedemption'); +const GeneralPermissionManager = artifacts.require('./GeneralPermissionManager'); +const PolyTokenFaucet = artifacts.require('./PolyTokenFaucet.sol'); + +const Web3 = require('web3'); +const BigNumber = require('bignumber.js'); +const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")) // Hardcoded development port + +contract('TrackedRedemption', accounts => { + + // Accounts Variable declaration + let account_polymath; + let account_issuer; + let token_owner; + let account_investor1; + let account_investor2; + let account_investor3; + let account_investor4; + let account_temp; + + // investor Details + let fromTime = latestTime(); + let toTime = latestTime(); + let expiryTime = toTime + duration.days(15); + + let message = "Transaction Should Fail!"; + + // Contract Instance Declaration + let I_GeneralPermissionManagerFactory; + let I_SecurityTokenRegistryProxy; + let I_GeneralTransferManagerFactory; + let I_TrackedRedemptionFactory; + let I_GeneralPermissionManager; + let I_TrackedRedemption; + let I_GeneralTransferManager; + let I_ExchangeTransferManager; + let I_ModuleRegistryProxy; + let I_ModuleRegistry; + let I_FeatureRegistry; + let I_SecurityTokenRegistry; + let I_STRProxied; + let I_STFactory; + let I_SecurityToken; + let I_PolyToken; + let I_MRProxied; + let I_PolymathRegistry; + + // SecurityToken Details + const name = "Team"; + const symbol = "sap"; + const tokenDetails = "This is equity type of issuance"; + const decimals = 18; + const contact = "team@polymath.network"; + let snapId; + // Module key + const delegateManagerKey = 1; + const transferManagerKey = 2; + const stoKey = 3; + const checkpointKey = 4; + const burnKey = 5; + + // Initial fee for ticker registry and security token registry + const initRegFee = web3.utils.toWei("250"); + const STRProxyParameters = ['address', 'address', 'uint256', 'uint256', 'address', 'address']; + const MRProxyParameters = ['address', 'address']; + + before(async() => { + // Accounts setup + account_polymath = accounts[0]; + account_issuer = accounts[1]; + + token_owner = account_issuer; + + account_investor1 = accounts[6]; + account_investor2 = accounts[7]; + account_investor3 = accounts[8]; + account_investor4 = accounts[9]; + account_temp = accounts[2]; + + // ----------- POLYMATH NETWORK Configuration ------------ + + // Step 0: Deploy the PolymathRegistry + I_PolymathRegistry = await PolymathRegistry.new({from: account_polymath}); + + // Step 1: Deploy the token Faucet and Mint tokens for token_owner + I_PolyToken = await PolyTokenFaucet.new(); + await I_PolyToken.getTokens((10000 * Math.pow(10, 18)), token_owner); + + // Step 2: Deploy the FeatureRegistry + + I_FeatureRegistry = await FeatureRegistry.new( + I_PolymathRegistry.address, + { + from: account_polymath + }); + + // STEP 3: Deploy the ModuleRegistry + + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); + // Step 3 (b): Deploy the proxy and attach the implementation contract to it + I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); + let bytesMRProxy = encodeProxyCall(MRProxyParameters, [I_PolymathRegistry.address, account_polymath]); + await I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesMRProxy, {from: account_polymath}); + I_MRProxied = await ModuleRegistry.at(I_ModuleRegistryProxy.address); + + // STEP 4: Deploy the GeneralTransferManagerFactory + + I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, {from:account_polymath}); + + assert.notEqual( + I_GeneralTransferManagerFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "GeneralTransferManagerFactory contract was not deployed" + ); + + // STEP 5: Deploy the GeneralDelegateManagerFactory + + I_GeneralPermissionManagerFactory = await GeneralPermissionManagerFactory.new(I_PolyToken.address, 0, 0, 0, {from:account_polymath}); + + assert.notEqual( + I_GeneralPermissionManagerFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "GeneralDelegateManagerFactory contract was not deployed" + ); + + // STEP 4: Deploy the TrackedRedemption + I_TrackedRedemptionFactory = await TrackedRedemptionFactory.new(I_PolyToken.address, 0, 0, 0, {from:account_polymath}); + assert.notEqual( + I_TrackedRedemptionFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "TrackedRedemptionFactory contract was not deployed" + ); + + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the TrackedRedemptionFactory + await I_MRProxied.registerModule(I_TrackedRedemptionFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_TrackedRedemptionFactory.address, true, { from: account_polymath }); + + // Step 6: Deploy the STFactory contract + + I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); + + assert.notEqual( + I_STFactory.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "STFactory contract was not deployed", + ); + + // Step 7: Deploy the SecurityTokenRegistry contract + + I_SecurityTokenRegistry = await SecurityTokenRegistry.new({from: account_polymath }); + + assert.notEqual( + I_SecurityTokenRegistry.address.valueOf(), + "0x0000000000000000000000000000000000000000", + "SecurityTokenRegistry contract was not deployed", + ); + + // Step 8: Deploy the proxy and attach the implementation contract to it. + I_SecurityTokenRegistryProxy = await SecurityTokenRegistryProxy.new({from: account_polymath}); + let bytesProxy = encodeProxyCall(STRProxyParameters, [I_PolymathRegistry.address, I_STFactory.address, initRegFee, initRegFee, I_PolyToken.address, account_polymath]); + await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); + I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); + + // Step 9: update the registries addresses from the PolymathRegistry contract + await I_PolymathRegistry.changeAddress("PolyToken", I_PolyToken.address, {from: account_polymath}) + await I_PolymathRegistry.changeAddress("ModuleRegistry", I_ModuleRegistryProxy.address, {from: account_polymath}); + await I_PolymathRegistry.changeAddress("FeatureRegistry", I_FeatureRegistry.address, {from: account_polymath}); + await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); + await I_MRProxied.updateFromRegistry({from: account_polymath}); + + // Printing all the contract addresses + console.log(` + --------------------- Polymath Network Smart Contracts: --------------------- + PolymathRegistry: ${PolymathRegistry.address} + SecurityTokenRegistryProxy: ${SecurityTokenRegistryProxy.address} + SecurityTokenRegistry: ${SecurityTokenRegistry.address} + ModuleRegistry: ${ModuleRegistry.address} + ModuleRegistryProxy: ${ModuleRegistryProxy.address} + FeatureRegistry: ${FeatureRegistry.address} + + STFactory: ${STFactory.address} + GeneralTransferManagerFactory: ${GeneralTransferManagerFactory.address} + GeneralPermissionManagerFactory: ${GeneralPermissionManagerFactory.address} + + TrackedRedemptionFactory: ${I_TrackedRedemptionFactory.address} + ----------------------------------------------------------------------------- + `); + }); + + describe("Generate the SecurityToken", async() => { + + it("Should register the ticker before the generation of the security token", async () => { + await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); + let tx = await I_STRProxied.registerTicker(token_owner, symbol, contact, { from : token_owner }); + assert.equal(tx.logs[0].args._owner, token_owner); + assert.equal(tx.logs[0].args._ticker, symbol.toUpperCase()); + }); + + it("Should generate the new security token with the same symbol as registered above", async () => { + await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); + let _blockNo = latestBlock(); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + + // Verify the successful generation of the security token + assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); + + I_SecurityToken = SecurityToken.at(tx.logs[1].args._securityTokenAddress); + + const log = await promisifyLogWatch(I_SecurityToken.ModuleAdded({from: _blockNo}), 1); + + // Verify that GeneralTransferManager module get added successfully or not + assert.equal(log.args._type.toNumber(), 2); + assert.equal( + web3.utils.toAscii(log.args._name) + .replace(/\u0000/g, ''), + "GeneralTransferManager" + ); + }); + + it("Should intialize the auto attached modules", async () => { + let moduleData = await I_SecurityToken.modules(2, 0); + I_GeneralTransferManager = GeneralTransferManager.at(moduleData); + + }); + + it("Should successfully attach the TrackedRedemption with the security token", async () => { + const tx = await I_SecurityToken.addModule(I_TrackedRedemptionFactory.address, "", 0, 0, { from: token_owner }); + assert.equal(tx.logs[2].args._type.toNumber(), burnKey, "TrackedRedemption doesn't get deployed"); + assert.equal( + web3.utils.toAscii(tx.logs[2].args._name) + .replace(/\u0000/g, ''), + "TrackedRedemption", + "TrackedRedemption module was not added" + ); + I_TrackedRedemption = TrackedRedemption.at(tx.logs[2].args._module); + }); + }); + + describe("Make Redemptions", async() => { + + it("Buy some tokens for account_investor1 (1 ETH)", async() => { + // Add the Investor in to the whitelist + + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor1, + latestTime(), + latestTime(), + latestTime() + duration.days(30), + true, + { + from: account_issuer, + gas: 500000 + }); + + assert.equal(tx.logs[0].args._investor.toLowerCase(), account_investor1.toLowerCase(), "Failed in adding the investor in whitelist"); + + // Jump time + await increaseTime(5000); + + // Mint some tokens + await I_SecurityToken.mint(account_investor1, web3.utils.toWei('1', 'ether'), { from: token_owner }); + + assert.equal( + (await I_SecurityToken.balanceOf(account_investor1)).toNumber(), + web3.utils.toWei('1', 'ether') + ); + }); + + it("Buy some tokens for account_investor2 (2 ETH)", async() => { + // Add the Investor in to the whitelist + + let tx = await I_GeneralTransferManager.modifyWhitelist( + account_investor2, + latestTime(), + latestTime(), + latestTime() + duration.days(30), + true, + { + from: account_issuer, + gas: 500000 + }); + + assert.equal(tx.logs[0].args._investor.toLowerCase(), account_investor2.toLowerCase(), "Failed in adding the investor in whitelist"); + + // Mint some tokens + await I_SecurityToken.mint(account_investor2, web3.utils.toWei('2', 'ether'), { from: token_owner }); + + assert.equal( + (await I_SecurityToken.balanceOf(account_investor2)).toNumber(), + web3.utils.toWei('2', 'ether') + ); + }); + + it("Redeem some tokens - fail insufficient allowance", async() => { + await I_GeneralTransferManager.changeAllowAllBurnTransfers(true, {from : token_owner}); + + let errorThrown = false; + try { + let tx = await I_TrackedRedemption.redeemTokens(web3.utils.toWei('1', 'ether'), {from: account_investor1}); + } catch(error) { + console.log(` tx -> failed insufficent allowance`.grey); + ensureException(error); + errorThrown = true; + } + assert.ok(errorThrown, message); + }); + + it("Redeem some tokens", async() => { + await I_SecurityToken.approve(I_TrackedRedemption.address, web3.utils.toWei('1', 'ether'), {from: account_investor1}); + let tx = await I_TrackedRedemption.redeemTokens(web3.utils.toWei('1', 'ether'), {from: account_investor1}); + console.log(JSON.stringify(tx.logs)); + assert.equal(tx.logs[0].args._investor.toLowerCase(), account_investor1.toLowerCase(), "Mismatch address"); + assert.equal(tx.logs[0].args._value, web3.utils.toWei('1', 'ether'), "Wrong value"); + }); + + it("Get the init data", async() => { + let tx = await I_TrackedRedemption.getInitFunction.call(); + assert.equal(web3.utils.toAscii(tx).replace(/\u0000/g, ''),0); + }); + + it("Should get the listed permissions", async() => { + let tx = await I_TrackedRedemption.getPermissions.call(); + assert.equal(tx.length,0); + }); + + describe("Test cases for the TrackedRedemptionFactory", async() => { + it("should get the exact details of the factory", async() => { + assert.equal((await I_TrackedRedemptionFactory.setupCost.call()).toNumber(), 0); + assert.equal(await I_TrackedRedemptionFactory.getType.call(), 5); + assert.equal(web3.utils.toAscii(await I_TrackedRedemptionFactory.getName.call()) + .replace(/\u0000/g, ''), + "TrackedRedemption", + "Wrong Module added"); + assert.equal(await I_TrackedRedemptionFactory.getDescription.call(), + "Track token redemptions", + "Wrong Module added"); + assert.equal(await I_TrackedRedemptionFactory.getTitle.call(), + "Tracked Redemption", + "Wrong Module added"); + assert.equal(await I_TrackedRedemptionFactory.getInstructions.call(), + "Allows an investor to redeem security tokens which are tracked by this module", + "Wrong Module added"); + let tags = await I_TrackedRedemptionFactory.getTags.call(); + assert.equal(tags.length, 2); + + }); + }); + + }); + +}); From c92ed874324c721423f47ab081a3ff7cdbc3dbdf Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 1 Oct 2018 12:53:08 +0530 Subject: [PATCH 24/63] minor fixes to reduce the size --- contracts/SecurityTokenRegistry.sol | 24 +++++++++++++------ .../interfaces/ISecurityTokenRegistry.sol | 6 +++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 671cd5c82..b8e73dbe1 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -117,7 +117,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if (msg.sender == getAddress(Encoder.getKey("owner"))) _; else { - require(!getBool(Encoder.getKey("paused")), "Already paused"); + require(!isPaused(), "Already paused"); _; } } @@ -126,7 +126,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused and ignore is msg.sender is owner. */ modifier whenNotPaused() { - require(!getBool(Encoder.getKey("paused")), "Already paused"); + require(!isPaused(), "Already paused"); _; } @@ -135,10 +135,11 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { - require(getBool(Encoder.getKey("paused")), "Should not be paused"); + require(isPaused(), "Should not be paused"); _; } + ///////////////////////////// // Initialization ///////////////////////////// @@ -281,8 +282,9 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _ticker is the ticker symbol */ function _setTickerOwnership(address _owner, string _ticker) internal { - uint256 length = uint256(getArrayBytes32(Encoder.getKey("userToTickers", _owner)).length); - pushArray(Encoder.getKey("userToTickers", _owner), Util.stringToBytes32(_ticker)); + bytes32 _ownerKey = Encoder.getKey("userToTickers", _owner); + uint256 length = uint256(getArrayBytes32(_ownerKey).length); + pushArray(_ownerKey, Util.stringToBytes32(_ticker)); set(Encoder.getKey("tickerIndex", _ticker), length); bytes32 seenKey = Encoder.getKey("seenUsers", _owner); if (!getBool(seenKey)) { @@ -339,7 +341,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { bytes32[] memory tickers = getArrayBytes32(ownerKey); assert(index < tickers.length); assert(_tickerOwner(_ticker) == _owner); - deleteArrayBytes32(Encoder.getKey("userToTickers", _owner), index); + deleteArrayBytes32(ownerKey, index); if (tickers.length > index) { bytes32 switchedTicker = tickers[index]; set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), index); @@ -459,7 +461,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(bytes(_name).length > 0 && bytes(_ticker).length > 0, "Ticker length > 0"); string memory ticker = Util.upper(_ticker); bytes32 statusKey = Encoder.getKey("registeredTickers_status", ticker); - require(getBool(statusKey) != true, "Already deployed"); + require(!getBool(statusKey), "Already deployed"); set(statusKey, true); require(_tickerOwner(ticker) == msg.sender, "Not authorised"); require(getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)) >= now, "Ticker gets expired"); @@ -684,4 +686,12 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return getUint(Encoder.getKey("expiryLimit")); } + /** + * @notice Check whether the registry is paused or not + * @return bool + */ + function isPaused() public view returns(bool) { + return getBool(Encoder.getKey("paused")); + } + } diff --git a/contracts/interfaces/ISecurityTokenRegistry.sol b/contracts/interfaces/ISecurityTokenRegistry.sol index 87c02cc90..5231e8ef4 100644 --- a/contracts/interfaces/ISecurityTokenRegistry.sol +++ b/contracts/interfaces/ISecurityTokenRegistry.sol @@ -177,4 +177,10 @@ interface ISecurityTokenRegistry { */ function getExpiryLimit() external view returns(uint256); + /** + * @notice Check whether the registry is paused or not + * @return bool + */ + function isPaused() public view returns(bool); + } From 0ea44ab58ac59603134ab1d051048b97e091a5aa Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 10:31:42 +0100 Subject: [PATCH 25/63] Revert changes to setProtocol --- contracts/SecurityTokenRegistry.sol | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index b8e73dbe1..9e568c94c 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -164,7 +164,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { set(Encoder.getKey("paused"), false); set(Encoder.getKey("owner"), _owner); set(Encoder.getKey("polymathRegistry"), _polymathRegistry); - setProtocolVersion(_STFactory, uint8(0), uint8(0), uint8(2)); + _setProtocolVersion(_STFactory, uint8(0), uint8(0), uint8(2)); set(Encoder.getKey("initialised"), true); } @@ -627,16 +627,22 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @param _minor Minor version of the proxy. * @param _patch Patch version of the proxy */ - function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) public { - uint8[] memory version = new uint8[](3); - version[0] = _major; - version[1] = _minor; - version[2] = _patch; - uint24 packedVersion = VersionUtils.pack(_major, _minor, _patch); - require(VersionUtils.isValidVersion(getProtocolVersion(), version),"Invalid version"); - set(Encoder.getKey("latestVersion"), uint256(packedVersion)); + function setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) external onlyOwner { + _setProtocolVersion(_STFactoryAddress, _major, _minor, _patch); + } + + /** + * @notice Internal - Changes the protocol version and the SecurityToken contract + */ + function _setProtocolVersion(address _STFactoryAddress, uint8 _major, uint8 _minor, uint8 _patch) internal { + uint8[] memory _version = new uint8[](3); + _version[0] = _major; + _version[1] = _minor; + _version[2] = _patch; + uint24 _packedVersion = VersionUtils.pack(_major, _minor, _patch); + require(VersionUtils.isValidVersion(getProtocolVersion(), _version),"In-valid version"); + set(Encoder.getKey("latestVersion"), uint256(_packedVersion)); set(Encoder.getKey("protocolVersionST", getUint(Encoder.getKey("latestVersion"))), _STFactoryAddress); - /* set(Encoder.getKey("protocolVersionST", uint256(_packedVersion)), _STFactoryAddress); */ } /** From 04fb3a18f3b00299d4b1bef0e46edc7a23642836 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 12:00:53 +0100 Subject: [PATCH 26/63] Only allow STs to be added if there is a valid ticker registration first --- contracts/SecurityTokenRegistry.sol | 9 +++++++-- test/n_security_token_registry.js | 11 +++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 9e568c94c..8b7a3bd77 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -236,6 +236,10 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if (_tickerStatus(_ticker) && !_status) { set(Encoder.getKey("tickerToSecurityToken", _ticker), address(0)); } + // If status is true, there must be a security token linked to the ticker already + if (_status) { + require(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker)) != address(0), "Token not registered"); + } _addTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _status, true); } @@ -500,9 +504,10 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_deployedAt != 0 && _owner != address(0), "0 value params not allowed"); string memory ticker = Util.upper(_ticker); require(_securityToken != address(0), "ST address is 0x"); - // If ticker didn't previously exist, it will be created - _modifyTicker(_owner, ticker, _name, getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)), true); + // If ticker doesn't exist, then we will fail - must call modifyTicker first + require(_tickerOwner(ticker) != address(0), "Ticker not registered"); set(Encoder.getKey("tickerToSecurityToken", ticker), _securityToken); + _modifyTicker(_owner, ticker, _name, getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)), true); _storeSecurityTokenData(_securityToken, ticker, _tokenDetails, _deployedAt); emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true); } diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index a729f2d37..1a47b82bf 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -757,6 +757,17 @@ contract('SecurityTokenRegistry', accounts => { it("Should successfully generate the custom token", async() => { // Fulfilling the TickerStatus.NN condition + let errorThrown = false; + try { + await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); + } catch(error) { + console.log(` tx revert -> because ticker not registered`.grey); + errorThrown = true; + ensureException(error); + } + assert.ok(errorThrown, message); + await I_STRProxied.modifyTicker(account_temp, "LOG2", "LOGAN2", latestTime(), latestTime() + duration.days(10), false, {from: account_polymath}); + await increaseTime(duration.days(1)); let tx = await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); assert.equal(tx.logs[1].args._ticker, "LOG2", "Symbol should match with the registered symbol"); assert.equal(tx.logs[1].args._securityTokenAddress, dummy_token, `Address of the SecurityToken should be matched with the input value of addCustomSecurityToken`); From 6621d9e66cf5f1da52cb4c214d57924a97b1e4e9 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 12:15:42 +0100 Subject: [PATCH 27/63] Change logic to allow tickers to be registered directly when modifying security tokens --- contracts/SecurityTokenRegistry.sol | 10 +++++++--- test/n_security_token_registry.js | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 8b7a3bd77..d3c12ac19 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -504,10 +504,14 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_deployedAt != 0 && _owner != address(0), "0 value params not allowed"); string memory ticker = Util.upper(_ticker); require(_securityToken != address(0), "ST address is 0x"); - // If ticker doesn't exist, then we will fail - must call modifyTicker first - require(_tickerOwner(ticker) != address(0), "Ticker not registered"); + uint256 registrationTime = getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)); + uint256 expiryTime = getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)); + if (registrationTime == 0) { + registrationTime = now; + expiryTime = registrationTime.add(getExpiryLimit()); + } set(Encoder.getKey("tickerToSecurityToken", ticker), _securityToken); - _modifyTicker(_owner, ticker, _name, getUint(Encoder.getKey("registeredTickers_registrationDate", ticker)), getUint(Encoder.getKey("registeredTickers_expiryDate", ticker)), true); + _modifyTicker(_owner, ticker, _name, registrationTime, expiryTime, true); _storeSecurityTokenData(_securityToken, ticker, _tokenDetails, _deployedAt); emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true); } diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index 1a47b82bf..5b09d6160 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -757,17 +757,17 @@ contract('SecurityTokenRegistry', accounts => { it("Should successfully generate the custom token", async() => { // Fulfilling the TickerStatus.NN condition - let errorThrown = false; - try { - await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); - } catch(error) { - console.log(` tx revert -> because ticker not registered`.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - await I_STRProxied.modifyTicker(account_temp, "LOG2", "LOGAN2", latestTime(), latestTime() + duration.days(10), false, {from: account_polymath}); - await increaseTime(duration.days(1)); + // let errorThrown = false; + // try { + // await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); + // } catch(error) { + // console.log(` tx revert -> because ticker not registered`.grey); + // errorThrown = true; + // ensureException(error); + // } + // assert.ok(errorThrown, message); + // await I_STRProxied.modifyTicker(account_temp, "LOG2", "LOGAN2", latestTime(), latestTime() + duration.days(10), false, {from: account_polymath}); + // await increaseTime(duration.days(1)); let tx = await I_STRProxied.modifySecurityToken("LOGAN2", "LOG2", account_temp, dummy_token, "I am custom ST", latestTime(), {from: account_polymath}); assert.equal(tx.logs[1].args._ticker, "LOG2", "Symbol should match with the registered symbol"); assert.equal(tx.logs[1].args._securityTokenAddress, dummy_token, `Address of the SecurityToken should be matched with the input value of addCustomSecurityToken`); From 6deb8e2c29490e3cde62c3087675d02d66d07f2e Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Mon, 1 Oct 2018 10:09:28 -0300 Subject: [PATCH 28/63] CLI: STR getters for fees and expiry limit --- CLI/commands/ST20Generator.js | 6 ++---- CLI/commands/TickerRollForward.js | 4 +--- CLI/commands/contract_manager.js | 9 +++------ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index 27ae398b2..73a674434 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -19,8 +19,6 @@ let tokenSymbol; let selectedSTO; const STO_KEY = 3; -const REG_FEE_KEY = 'tickerRegFee'; -const LAUNCH_FEE_KEY = 'stLaunchFee'; const cappedSTOFee = 20000; const usdTieredSTOFee = 100000; const tokenDetails = ""; @@ -111,7 +109,7 @@ async function step_ticker_reg(){ console.log('\n\x1b[34m%s\x1b[0m',"Token Creation - Symbol Registration"); let available = false; - let regFee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); + let regFee = web3.utils.fromWei(await securityTokenRegistry.methods.getTickerRegistrationFee().call()); while (!available) { console.log(chalk.green(`\nRegistering the new token symbol requires ${regFee} POLY & deducted from '${Issuer.address}', Current balance is ${(await currentBalance(Issuer.address))} POLY\n`)); @@ -160,7 +158,7 @@ async function step_token_deploy(){ } else { console.log('\n\x1b[34m%s\x1b[0m',"Token Creation - Token Deployment"); - let launchFee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(LAUNCH_FEE_KEY)).call()); + let launchFee = web3.utils.fromWei(await securityTokenRegistry.methods.getSecurityTokenLaunchFee().call()); console.log(chalk.green(`\nToken deployment requires ${launchFee} POLY & deducted from '${Issuer.address}', Current balance is ${(await currentBalance(Issuer.address))} POLY\n`)); if (typeof _tokenConfig !== 'undefined' && _tokenConfig.hasOwnProperty('name')) { diff --git a/CLI/commands/TickerRollForward.js b/CLI/commands/TickerRollForward.js index 732eb1b97..97bd1f519 100644 --- a/CLI/commands/TickerRollForward.js +++ b/CLI/commands/TickerRollForward.js @@ -13,8 +13,6 @@ var abis = require('./helpers/contract_abis'); let remoteNetwork = process.argv.slice(2)[0]; //batch size ///////////////////////// GLOBAL VARS ///////////////////////// -const REG_FEE_KEY = 'tickerRegFee'; - let ticker_data = []; let registered_tickers = []; let failed_tickers = []; @@ -80,7 +78,7 @@ async function readFile() { async function registerTickers() { // Poly approval for registration fees let polyBalance = BigNumber(await polyToken.methods.balanceOf(Issuer.address).call()); - let fee = web3.utils.fromWei(await securityTokenRegistry.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); + let fee = web3.utils.fromWei(await securityTokenRegistry.methods.getTickerRegistrationFee().call()); let totalFee = BigNumber(ticker_data.length).mul(fee); if (totalFee.gt(polyBalance)) { diff --git a/CLI/commands/contract_manager.js b/CLI/commands/contract_manager.js index 60af89396..0406dc191 100644 --- a/CLI/commands/contract_manager.js +++ b/CLI/commands/contract_manager.js @@ -14,9 +14,6 @@ var contracts = require('./helpers/contract_addresses'); var abis = require('./helpers/contract_abis'); const OWNER_KEY = 'owner'; -const REG_FEE_KEY = 'tickerRegFee'; -const LAUNCH_FEE_KEY = 'stLaunchFee'; -const EXPIRY_LIMIT_KEY = 'expiryLimit'; // App flow let currentContract = null; @@ -168,7 +165,7 @@ async function strActions() { console.log(chalk.green(`Security Token has been updated successfuly`)); break; case 'Change Expiry Limit': - let currentExpiryLimit = await currentContract.methods.getUintValues(web3.utils.soliditySha3(EXPIRY_LIMIT_KEY)).call(); + let currentExpiryLimit = await currentContract.methods.getExpiryLimit().call(); console.log(chalk.yellow(`Current expiry limit is ${Math.floor(parseInt(currentExpiryLimit)/60/60/24)} days`)); let newExpiryLimit = duration.days(readlineSync.questionInt('Enter a new value in days for expiry limit: ')); let changeExpiryLimitAction = currentContract.methods.changeExpiryLimit(newExpiryLimit); @@ -177,7 +174,7 @@ async function strActions() { console.log(chalk.green(`Expiry limit was changed successfuly. New limit is ${Math.floor(parseInt(changeExpiryLimitEvent._newExpiry)/60/60/24)} days\n`)); break; case 'Change registration fee': - let currentRegFee = web3.utils.fromWei(await currentContract.methods.getUintValues(web3.utils.soliditySha3(REG_FEE_KEY)).call()); + let currentRegFee = web3.utils.fromWei(await currentContract.methods.getTickerRegistrationFee().call()); console.log(chalk.yellow(`\nCurrent ticker registration fee is ${currentRegFee} POLY`)); let newRegFee = web3.utils.toWei(readlineSync.questionInt('Enter a new value in POLY for ticker registration fee: ').toString()); let changeRegFeeAction = currentContract.methods.changeTickerRegistrationFee(newRegFee); @@ -186,7 +183,7 @@ async function strActions() { console.log(chalk.green(`Fee was changed successfuly. New fee is ${web3.utils.fromWei(changeRegFeeEvent._newFee)} POLY\n`)); break; case 'Change ST launch fee': - let currentLaunchFee = web3.utils.fromWei(await currentContract.methods.getUintValues(web3.utils.soliditySha3(LAUNCH_FEE_KEY)).call()); + let currentLaunchFee = web3.utils.fromWei(await currentContract.methods.getSecurityTokenLaunchFee().call()); console.log(chalk.yellow(`\nCurrent ST launch fee is ${currentLaunchFee} POLY`)); let newLaunchFee = web3.utils.toWei(readlineSync.questionInt('Enter a new value in POLY for ST launch fee: ').toString()); let changeLaunchFeeAction = currentContract.methods.changeSecurityLaunchFee(newLaunchFee); From 7eddf7df3113557442f71fc9090cce785404aad7 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Mon, 1 Oct 2018 10:12:15 -0300 Subject: [PATCH 29/63] CLI typo --- CLI/commands/contract_manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLI/commands/contract_manager.js b/CLI/commands/contract_manager.js index 0406dc191..07d89d48e 100644 --- a/CLI/commands/contract_manager.js +++ b/CLI/commands/contract_manager.js @@ -114,7 +114,7 @@ async function strActions() { console.log(chalk.green(`Ticker has been updated successfuly`)); break; case 'Remove Ticker': - let tickerToRemove = readlineSync.question('Enter the token symbol that you want to add or modify: '); + let tickerToRemove = readlineSync.question('Enter the token symbol that you want to remove: '); let tickerToRemoveDetails = await currentContract.methods.getTickerDetails(tickerToRemove).call(); if (tickerToRemoveDetails[1] == 0) { console.log(chalk.yellow(`${ticker} does not exist.`)); From 27e13cb999d9e6d86222c13d549664085b38895d Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 1 Oct 2018 18:48:23 +0530 Subject: [PATCH 30/63] minor fixes --- contracts/SecurityTokenRegistry.sol | 32 ++++++++++++------- .../interfaces/ISecurityTokenRegistry.sol | 8 ++++- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index d3c12ac19..926183238 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -86,7 +86,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { address indexed _owner, uint256 _addedAt, address _registrant, - bool _fromAdmin + bool _fromAdmin, + uint256 _registrationFee ); // Emit after ticker registration event RegisterTicker( @@ -95,7 +96,8 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { string _name, uint256 indexed _registrationDate, uint256 indexed _expiryDate, - bool _fromAdmin + bool _fromAdmin, + uint256 _registrationFee ); ///////////////////////////// @@ -106,7 +108,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { - require(msg.sender == getAddress(Encoder.getKey("owner"))); + require(msg.sender == owner()); _; } @@ -114,7 +116,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPausedOrOwner() { - if (msg.sender == getAddress(Encoder.getKey("owner"))) + if (msg.sender == owner()) _; else { require(!isPaused(), "Already paused"); @@ -194,16 +196,16 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if (previousOwner != address(0)) { _deleteTickerOwnership(previousOwner, ticker); } - _addTicker(_owner, ticker, _tokenName, now, now.add(getExpiryLimit()), false, false); + _addTicker(_owner, ticker, _tokenName, now, now.add(getExpiryLimit()), false, false, getTickerRegistrationFee()); } /** * @notice Internal - Sets the details of the ticker */ - function _addTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status, bool _fromAdmin) internal { + function _addTicker(address _owner, string _ticker, string _tokenName, uint256 _registrationDate, uint256 _expiryDate, bool _status, bool _fromAdmin, uint256 _fee) internal { _setTickerOwnership(_owner, _ticker); _storeTickerDetails(_ticker, _owner, _registrationDate, _expiryDate, _tokenName, _status); - emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _fromAdmin); + emit RegisterTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _fromAdmin, _fee); } /** @@ -240,7 +242,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if (_status) { require(getAddress(Encoder.getKey("tickerToSecurityToken", _ticker)) != address(0), "Token not registered"); } - _addTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _status, true); + _addTicker(_owner, _ticker, _tokenName, _registrationDate, _expiryDate, _status, true, uint256(0)); } function _tickerOwner(string _ticker) internal view returns(address) { @@ -486,7 +488,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { _storeSecurityTokenData(newSecurityTokenAddress, ticker, _tokenDetails, now); set(Encoder.getKey("tickerToSecurityToken", ticker), newSecurityTokenAddress); - emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false); + emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false, getSecurityTokenLaunchFee()); } /** @@ -513,7 +515,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { set(Encoder.getKey("tickerToSecurityToken", ticker), _securityToken); _modifyTicker(_owner, ticker, _name, registrationTime, expiryTime, true); _storeSecurityTokenData(_securityToken, ticker, _tokenDetails, _deployedAt); - emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true); + emit NewSecurityToken(ticker, _name, _securityToken, _owner, _deployedAt, msg.sender, true, getSecurityTokenLaunchFee()); } /** @@ -624,7 +626,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { require(_tokenContract != address(0)); IERC20 token = IERC20(_tokenContract); uint256 balance = token.balanceOf(address(this)); - require(token.transfer(getAddress(Encoder.getKey("owner")), balance)); + require(token.transfer(owner(), balance)); } /** @@ -709,4 +711,12 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { return getBool(Encoder.getKey("paused")); } + /** + * @notice Gets the owner of the contract + * @return address owner + */ + function owner() public view returns(address) { + return getAddress(Encoder.getKey("owner")); + } + } diff --git a/contracts/interfaces/ISecurityTokenRegistry.sol b/contracts/interfaces/ISecurityTokenRegistry.sol index 5231e8ef4..2bacd39d7 100644 --- a/contracts/interfaces/ISecurityTokenRegistry.sol +++ b/contracts/interfaces/ISecurityTokenRegistry.sol @@ -181,6 +181,12 @@ interface ISecurityTokenRegistry { * @notice Check whether the registry is paused or not * @return bool */ - function isPaused() public view returns(bool); + function isPaused() external view returns(bool); + + /** + * @notice Gets the owner of the contract + * @return address owner + */ + function owner() external view returns(address); } From d56957feb37a17526705e36417b402c30af27493 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 14:33:25 +0100 Subject: [PATCH 31/63] Minor change --- contracts/SecurityTokenRegistry.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 926183238..9c4c059ef 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -196,7 +196,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { if (previousOwner != address(0)) { _deleteTickerOwnership(previousOwner, ticker); } - _addTicker(_owner, ticker, _tokenName, now, now.add(getExpiryLimit()), false, false, getTickerRegistrationFee()); + _addTicker(_owner, ticker, _tokenName, now, now.add(getExpiryLimit()), false, false, tickerFee); } /** @@ -488,7 +488,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { _storeSecurityTokenData(newSecurityTokenAddress, ticker, _tokenDetails, now); set(Encoder.getKey("tickerToSecurityToken", ticker), newSecurityTokenAddress); - emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false, getSecurityTokenLaunchFee()); + emit NewSecurityToken(ticker, _name, newSecurityTokenAddress, msg.sender, now, msg.sender, false, launchFee); } /** From 712ec474295c5f6cf1abf00ae71c2e6c450b80d5 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 15:12:50 +0100 Subject: [PATCH 32/63] Fixes based on Satyam feedback --- contracts/tokens/SecurityToken.sol | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 219467ece..11eeec231 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -525,10 +525,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return bool success */ function transfer(address _to, uint256 _value) public returns (bool success) { - _adjustInvestorCount(msg.sender, _to, _value); - require(_verifyTransfer(msg.sender, _to, _value, true), "Transfer is not valid"); - _adjustBalanceCheckpoints(msg.sender); - _adjustBalanceCheckpoints(_to); + require(_updateTransfer(msg.sender, _to, _value), "Transfer is not valid"); require(super.transfer(_to, _value)); return true; } @@ -653,6 +650,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function _burn(address _from, uint256 _value) internal returns (bool) { require(_value <= balances[_from], "Value too high"); require(_updateTransfer(_from, address(0), _value), "Burn is not valid"); + _adjustTotalSupplyCheckpoints(); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit Burnt(_from, _value); @@ -676,8 +674,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr */ function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { require(_value <= allowed[_from][msg.sender]); - require(_burn(_from, _value)); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + require(_burn(_from, _value)); return true; } @@ -713,7 +711,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } } } - + /** * @notice Gets list of times that checkpoints were created * @return List of checkpoint times @@ -831,6 +829,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr function forceBurn(address _from, uint256 _value, bytes _data) public onlyController returns(bool) { require(_value <= balances[_from], "Value too high"); bool verified = _updateTransfer(_from, address(0), _value); + _adjustTotalSupplyCheckpoints(); balances[_from] = balances[_from].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit ForceBurn(msg.sender, _from, _value, verified, _data); From d348ff8d1ce1b04e916799b84b3847996a79a6a9 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 15:20:39 +0100 Subject: [PATCH 33/63] Modify require text --- contracts/tokens/SecurityToken.sol | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 11eeec231..c3d8ca8fb 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -164,12 +164,12 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr } modifier checkGranularity(uint256 _value) { - require(_value % granularity == 0, "Unable to modify token balances at this granularity"); + require(_value % granularity == 0, "Incorrect granularity"); _; } modifier isMintingAllowed() { - require(!mintingFrozen, "Minting is permanently frozen"); + require(!mintingFrozen, "Minting is frozen"); _; } @@ -182,8 +182,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @notice Revert if called by account which is not a controller */ modifier onlyController() { - require(msg.sender == controller); - require(!controllerDisabled); + require(msg.sender == controller, "Caller not controller"); + require(!controllerDisabled, "Controller disabled"); _; } @@ -249,14 +249,14 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr uint8 moduleType = moduleFactory.getType(); /* require(modules[moduleType].length < MAX_MODULES, "Limit of MAX MODULES is reached"); */ uint256 moduleCost = moduleFactory.getSetupCost(); - require(moduleCost <= _maxCost, "Max Cost is always be greater than module cost"); + require(moduleCost <= _maxCost, "Module cost too high"); //Approve fee for module - require(ERC20(polyToken).approve(_moduleFactory, moduleCost), "Not able to approve the module cost"); + require(ERC20(polyToken).approve(_moduleFactory, moduleCost), "Insufficient funds for cost"); //Creates instance of module from factory address module = moduleFactory.deploy(_data); require(modulesToData[module].module == address(0), "Module already exists"); //Approve ongoing budget - require(ERC20(polyToken).approve(module, _budget), "Not able to approve the budget"); + require(ERC20(polyToken).approve(module, _budget), "Insufficient funds for budget"); //Add to SecurityToken module map bytes32 moduleName = moduleFactory.getName(); modulesToData[module] = ModuleData(moduleName, module, _moduleFactory, false, moduleType, modules[moduleType].length, names[moduleName].length); @@ -271,7 +271,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to archive */ function archiveModule(address _module) external onlyOwner { - require(!modulesToData[_module].isArchived, "Module not unarchived"); + require(!modulesToData[_module].isArchived, "Module already archived"); require(modulesToData[_module].module != address(0), "Module missing"); emit ModuleArchived(modulesToData[_module].moduleType, _module, now); modulesToData[_module].isArchived = true; @@ -282,7 +282,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _module address of module to unarchive */ function unarchiveModule(address _module) external onlyOwner { - require(modulesToData[_module].isArchived, "Module not archived"); + require(modulesToData[_module].isArchived, "Module already unarchived"); emit ModuleUnarchived(modulesToData[_module].moduleType, _module, now); modulesToData[_module].isArchived = false; } @@ -363,7 +363,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value amount of POLY to withdraw */ function withdrawPoly(uint256 _value) external onlyOwner { - require(ERC20(polyToken).transfer(owner, _value), "In-sufficient balance"); + require(ERC20(polyToken).transfer(owner, _value), "Insufficient balance"); } /** @@ -640,7 +640,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @return success */ function mintMulti(address[] _investors, uint256[] _values) external onlyModuleOrOwner(MINT_KEY) returns (bool success) { - require(_investors.length == _values.length, "Mis-match in the length of the arrays"); + require(_investors.length == _values.length, "Incorrect inputs"); for (uint256 i = 0; i < _investors.length; i++) { mint(_investors[i], _values[i]); } @@ -663,7 +663,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value No. of tokens that get burned */ function burn(uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { - require(_burn(msg.sender, _value)); + require(_burn(msg.sender, _value), "Invalid burn"); return true; } @@ -673,9 +673,9 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr * @param _value No. of tokens that get burned */ function burnFrom(address _from, uint256 _value) checkGranularity(_value) onlyModule(BURN_KEY) public returns (bool) { - require(_value <= allowed[_from][msg.sender]); + require(_value <= allowed[_from][msg.sender], "Value too high"); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - require(_burn(_from, _value)); + require(_burn(_from, _value), "Invalid burn"); return true; } From 1420bce19088ec99464c091cbab15896a23b35b2 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Mon, 1 Oct 2018 12:56:16 -0300 Subject: [PATCH 34/63] CLI: Owner getter on STR --- CLI/commands/contract_manager.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CLI/commands/contract_manager.js b/CLI/commands/contract_manager.js index 07d89d48e..594522f6f 100644 --- a/CLI/commands/contract_manager.js +++ b/CLI/commands/contract_manager.js @@ -13,8 +13,6 @@ var global = require('./common/global'); var contracts = require('./helpers/contract_addresses'); var abis = require('./helpers/contract_abis'); -const OWNER_KEY = 'owner'; - // App flow let currentContract = null; @@ -76,7 +74,7 @@ async function selectContract() { async function strActions() { console.log('\n\x1b[34m%s\x1b[0m',"Security Token Registry - Main menu"); - let contractOwner = await currentContract.methods.getAddressValues(web3.utils.soliditySha3(OWNER_KEY)).call(); + let contractOwner = await currentContract.methods.owner().call(); if (contractOwner != Issuer.address) { console.log(chalk.red(`You are not the owner of this contract. Current owner is ${contractOwner}`)); From 555aa9b5ac6d87092f6eea32a095ea064ba19152 Mon Sep 17 00:00:00 2001 From: satyam Date: Mon, 1 Oct 2018 22:06:46 +0530 Subject: [PATCH 35/63] add version check in the getAvailableModulesOfType() --- contracts/ModuleRegistry.sol | 65 +++++++++++++++++------- contracts/interfaces/IModuleRegistry.sol | 12 +++++ test/k_module_registry.js | 3 +- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index c6b150385..e67c56cf0 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -62,7 +62,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { - require(msg.sender == getAddress(Encoder.getKey("owner"))); + require(msg.sender == owner()); _; } @@ -70,10 +70,10 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPausedOrOwner() { - if (msg.sender == getAddress(Encoder.getKey("owner"))) + if (msg.sender == owner()) _; else { - require(!getBool(Encoder.getKey("paused")), "Already paused"); + require(!isPaused(), "Already paused"); _; } } @@ -82,7 +82,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused and ignore is msg.sender is owner. */ modifier whenNotPaused() { - require(!getBool(Encoder.getKey("paused")), "Already paused"); + require(!isPaused(), "Already paused"); _; } @@ -90,7 +90,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { - require(getBool(Encoder.getKey("paused")), "Should not be paused"); + require(isPaused(), "Should not be paused"); _; } @@ -128,17 +128,22 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } else { require(getBool(Encoder.getKey('verified', _moduleFactory)), "ModuleFactory must be verified"); } - uint8[] memory _latestVersion = ISecurityToken(msg.sender).getVersion(); - uint8[] memory _lowerBound = IModuleFactory(_moduleFactory).getLowerSTVersionBounds(); - uint8[] memory _upperBound = IModuleFactory(_moduleFactory).getUpperSTVersionBounds(); - require(VersionUtils.compareLowerBound(_lowerBound, _latestVersion), "Version should not be below the lower bound of ST version requirement"); - require(VersionUtils.compareUpperBound(_upperBound, _latestVersion), "Version should not be above the upper bound of ST version requirement"); + 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); } } + function _isCompatibleModule(address _moduleFactory, address _securityToken) internal returns(bool) { + uint8[] memory _latestVersion = ISecurityToken(_securityToken).getVersion(); + uint8[] memory _lowerBound = IModuleFactory(_moduleFactory).getLowerSTVersionBounds(); + uint8[] memory _upperBound = IModuleFactory(_moduleFactory).getUpperSTVersionBounds(); + bool _isLowerAllowed = VersionUtils.compareLowerBound(_lowerBound, _latestVersion); + bool _isUpperAllowed = VersionUtils.compareUpperBound(_upperBound, _latestVersion); + return (_isLowerAllowed && _isUpperAllowed); + } + /** * @notice Called by the ModuleFactory owner to register new modules for SecurityTokens to use * @param _moduleFactory is the address of the module factory to be registered @@ -267,28 +272,35 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { function getAvailableModulesOfType(uint8 _moduleType, address _securityToken) external view returns (address[]) { uint256 _len = getArrayAddress(Encoder.getKey('moduleList', uint256(_moduleType))).length; address[] memory _addressList = getArrayAddress(Encoder.getKey('moduleList', uint256(_moduleType))); + bool _isCustomModuleAllowed = IFeatureRegistry(getAddress(Encoder.getKey('featureRegistry'))).getFeatureStatus("customModulesAllowed"); uint256 counter = 0; for (uint256 i = 0; i < _len; i++) { - if (IFeatureRegistry(getAddress(Encoder.getKey('featureRegistry'))).getFeatureStatus("customModulesAllowed")) { + if (_isCustomModuleAllowed) { if (IOwnable(_addressList[i]).owner() == IOwnable(_securityToken).owner() || getBool(Encoder.getKey('verified', _addressList[i]))) - counter++; + if(_isCompatibleModule(_addressList[i], _securityToken)) + counter++; } else if (getBool(Encoder.getKey('verified', _addressList[i]))) { - counter ++; + if(_isCompatibleModule(_addressList[i], _securityToken)) + counter++; } } address[] memory _tempArray = new address[](counter); counter = 0; for (uint256 j = 0; j < _len; j++) { - if (IFeatureRegistry(getAddress(Encoder.getKey('featureRegistry'))).getFeatureStatus("customModulesAllowed")) { + if (_isCustomModuleAllowed) { if (IOwnable(_addressList[j]).owner() == IOwnable(_securityToken).owner() || getBool(Encoder.getKey('verified', _addressList[j]))) { - _tempArray[counter] = _addressList[j]; - counter ++; + if(_isCompatibleModule(_addressList[j], _securityToken)) { + _tempArray[counter] = _addressList[j]; + counter ++; + } } } else if (getBool(Encoder.getKey('verified', _addressList[j]))) { - _tempArray[counter] = _addressList[j]; - counter ++; + if(_isCompatibleModule(_addressList[j], _securityToken)) { + _tempArray[counter] = _addressList[j]; + counter ++; + } } } return _tempArray; @@ -302,7 +314,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { require(_tokenContract != address(0)); IERC20 token = IERC20(_tokenContract); uint256 balance = token.balanceOf(address(this)); - require(token.transfer(getAddress(Encoder.getKey("owner")), balance)); + require(token.transfer(owner(), balance)); } /** @@ -331,4 +343,19 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { set(Encoder.getKey('polyToken'), IPolymathRegistry(_polymathRegistry).getAddress("PolyToken")); } + /** + * @notice Get the owner of the contract + * @return address owner + */ + function owner() public view returns(address) { + return getAddress(Encoder.getKey("owner")); + } + + /** + * @notice Check whether the contract operations is paused or not + * @return bool + */ + function isPaused() public view returns(bool) { + return getBool(Encoder.getKey("paused")); + } } diff --git a/contracts/interfaces/IModuleRegistry.sol b/contracts/interfaces/IModuleRegistry.sol index 59763bd57..bd1c071cd 100644 --- a/contracts/interfaces/IModuleRegistry.sol +++ b/contracts/interfaces/IModuleRegistry.sol @@ -79,4 +79,16 @@ interface IModuleRegistry { */ function updateFromRegistry() external; + /** + * @notice Get the owner of the contract + * @return address owner + */ + function owner() external view returns(address); + + /** + * @notice Check whether the contract operations is paused or not + * @return bool + */ + function isPaused() external view returns(bool); + } diff --git a/test/k_module_registry.js b/test/k_module_registry.js index 55cd836e0..2cda2da9b 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -557,13 +557,12 @@ contract('ModuleRegistry', accounts => { it("Should get the list of available modules when the customModulesAllowed", async() => { let _list = await I_MRProxied.getAvailableModulesOfType.call(3, I_SecurityToken.address); assert.equal(_list[0], I_CappedSTOFactory2.address); - assert.equal(_list[1], I_TestSTOFactory.address); }) it("Should get the list of available modules when the customModulesAllowed is not allowed", async() => { await I_FeatureRegistry.setFeatureStatus("customModulesAllowed", false, { from: account_polymath }); let _list = await I_MRProxied.getAvailableModulesOfType.call(3, I_SecurityToken.address); - assert.equal(_list[0], I_TestSTOFactory.address); + assert.equal(_list.length, 0); }) }) From 37c59f7e2085bb3d1a34f126f3ef7494be40b6d7 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 19:14:50 +0100 Subject: [PATCH 36/63] WIP --- contracts/ModuleRegistry.sol | 86 +++++++++++-------- contracts/interfaces/IModuleRegistry.sol | 54 ++++++------ .../interfaces/ISecurityTokenRegistry.sol | 2 +- 3 files changed, 76 insertions(+), 66 deletions(-) diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index c6b150385..a41f78cde 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -33,8 +33,6 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { // contains the list of verified modules mapping (address => bool) public verified; - // Contains the list of the available tags corresponding to each module type - mapping (uint8 => bytes32[]) public availableTags; */ /////////// @@ -70,7 +68,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @notice Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPausedOrOwner() { - if (msg.sender == getAddress(Encoder.getKey("owner"))) + if (msg.sender == getAddress(Encoder.getKey("owner"))) _; else { require(!getBool(Encoder.getKey("paused")), "Already paused"); @@ -106,7 +104,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { function initialize(address _polymathRegistry, address _owner) external payable { require(!getBool(Encoder.getKey("initialised"))); - require(_owner != address(0) && _polymathRegistry != address(0), "0x address is in-valid"); + require(_owner != address(0) && _polymathRegistry != address(0), "0x address is invalid"); set(Encoder.getKey("polymathRegistry"), _polymathRegistry); set(Encoder.getKey("owner"), _owner); set(Encoder.getKey("initialised"), true); @@ -144,6 +142,9 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _moduleFactory is the address of the module factory to be registered */ function registerModule(address _moduleFactory) external whenNotPausedOrOwner { + if (IFeatureRegistry(getAddress(Encoder.getKey('featureRegistry'))).getFeatureStatus("customModulesAllowed")) { + require(msg.sender == getAddress(Encoder.getKey("owner")), "Only owner allowed to register modules"); + } require(getUint(Encoder.getKey('registry', _moduleFactory)) == 0, "Module factory should not be pre-registered"); IModuleFactory moduleFactory = IModuleFactory(_moduleFactory); uint8 moduleType = moduleFactory.getType(); @@ -172,7 +173,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { // pop from array and re-order if (index != last) { // moduleList[moduleType][index] = temp; - setArrayIndexValue(Encoder.getKey('moduleList', moduleType), index, temp); + setArrayIndexValue(Encoder.getKey('moduleList', moduleType), index, temp); set(Encoder.getKey('moduleListIndex', temp), index); } deleteArrayAddress(Encoder.getKey('moduleList', moduleType), last); @@ -196,48 +197,61 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _moduleFactory is the address of the module factory to be verified * @return bool */ - function verifyModule(address _moduleFactory, bool _verified) external onlyOwner returns(bool) { + function verifyModule(address _moduleFactory, bool _verified) external onlyOwner { require(getUint(Encoder.getKey('registry', _moduleFactory)) != uint256(0), "Module factory must be registered"); set(Encoder.getKey('verified', _moduleFactory), _verified); emit ModuleVerified(_moduleFactory, _verified); - return true; } /** - * @notice Adds a list of tags for the specified Module Factory - * @dev This function is susceptible to hit the block gas limit if too many tags get added. - * @param _moduleType is the module type. - * @param _tag is the list of tags to add. + * @notice Returns all the tags related to the a module type which are valid for the given token + * @param _moduleType is the module type + * @param _securityToken is the token + * @return list of tags + * @return corresponding list of module factories */ - function addTagByModuleType(uint8 _moduleType, bytes32[] _tag) external onlyOwner { - for (uint8 i = 0; i < _tag.length; i++) { - pushArray(Encoder.getKey('availableTags', uint256(_moduleType)), _tag[i]); - } - } + function getTagsByTypeAndToken(uint8 _moduleType, address _securityToken) external view returns(bytes32[], address[]) { + address[] memory modules = getModulesByTypeAndToken(_moduleType, _securityToken); + return _tagsByModules(modules); + } /** - * @notice Removes the tag for specified Module Factory - * @dev This function is susceptible to hit the block gas limit if too many tags get removed. - * @param _moduleType is the module type. - * @param _removedTags is the list of tags to remove + * @notice Returns all the tags related to the a module type which are valid for the given token + * @param _moduleType is the module type + * @return list of tags + * @return corresponding list of module factories */ - function removeTagByModuleType(uint8 _moduleType, bytes32[] _removedTags) external onlyOwner { - for (uint8 i = 0; i < getArrayBytes32(Encoder.getKey('availableTags', uint256(_moduleType))).length; i++) { - for (uint8 j = 0; j < _removedTags.length; j++) { - if (getArrayBytes32(Encoder.getKey('availableTags', uint256(_moduleType)))[i] == _removedTags[j]) { - deleteArrayBytes32(Encoder.getKey('availableTags', uint256(_moduleType)), uint256(i)); - } - } - } + function getTagsByType(uint8 _moduleType) external view returns(bytes32[], address[]) { + address[] memory modules = getModulesByType(_moduleType); + return _tagsByModules(modules); } /** - * @notice Returns all the tags related to the functionality of the entered Module Factory. - * @param _moduleType is the module type - * @return bytes32 array + * @notice Returns all the tags related to the modules provided + * @param _modules modules to return tags for + * @return list of tags + * @return corresponding list of module factories */ - function getTagByModuleType(uint8 _moduleType) public view returns(bytes32[]) { - return getArrayBytes32(Encoder.getKey('availableTags', uint256(_moduleType))); + function _tagsByModules(address[] _modules) internal view returns(bytes32[], address[]) { + uint256 counter = 0; + uint256 i; + uint256 j; + for (i = 0; i < _modules.length; i++) { + counter = counter + IModuleFactory(_modules[i]).getTags().length; + } + bytes32[] memory tags = new bytes32[](counter); + address[] memory modules = new address[](counter); + bytes32[] memory tempTags; + counter = 0; + for (i = 0; i < _modules.length; i++) { + tempTags = IModuleFactory(_modules[i]).getTags(); + for (j = 0; j < tempTags.length; j++) { + tags[counter] = tempTags[j]; + modules[counter] = _modules[i]; + counter++; + } + } + return (tags, modules); } /** @@ -245,7 +259,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _factoryAddress is the address of the module factory * @return address array which contains the list of securityTokens that use that module factory */ - function getReputationOfFactory(address _factoryAddress) external view returns(address[]) { + function getReputationByFactory(address _factoryAddress) external view returns(address[]) { return getArrayAddress(Encoder.getKey('reputation', _factoryAddress)); } @@ -254,7 +268,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _moduleType Type of Module * @return address array that contains the list of addresses of module factory contracts. */ - function getModuleListOfType(uint8 _moduleType) external view returns(address[]) { + function getModulesByType(uint8 _moduleType) public view returns(address[]) { return getArrayAddress(Encoder.getKey('moduleList', uint256(_moduleType))); } @@ -264,7 +278,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { * @param _securityToken is the address of SecurityToken * @return address array that contains the list of available addresses of module factory contracts. */ - function getAvailableModulesOfType(uint8 _moduleType, address _securityToken) external view returns (address[]) { + function getModulesByTypeAndToken(uint8 _moduleType, address _securityToken) public view returns (address[]) { uint256 _len = getArrayAddress(Encoder.getKey('moduleList', uint256(_moduleType))).length; address[] memory _addressList = getArrayAddress(Encoder.getKey('moduleList', uint256(_moduleType))); uint256 counter = 0; diff --git a/contracts/interfaces/IModuleRegistry.sol b/contracts/interfaces/IModuleRegistry.sol index 59763bd57..a5276c7a1 100644 --- a/contracts/interfaces/IModuleRegistry.sol +++ b/contracts/interfaces/IModuleRegistry.sol @@ -23,56 +23,52 @@ interface IModuleRegistry { */ function removeModule(address _moduleFactory) external; - /** - * @notice Use to get all the tags releated to the functionality of the Module Factory. - * @param _moduleType Type of module - */ - function getTagByModuleType(uint8 _moduleType) external view returns(bytes32[]); - /** * @notice Called by Polymath to verify modules for SecurityToken to use. * @notice A module can not be used by an ST unless first approved/verified by Polymath * @notice (The only exception to this is that the author of the module is the owner of the ST) * @param _moduleFactory is the address of the module factory to be registered - * @return bool */ - function verifyModule(address _moduleFactory, bool _verified) external returns(bool); + function verifyModule(address _moduleFactory, bool _verified) external; /** - * @notice Add the tag for specified Module Factory - * @param _moduleType Type of module. - * @param _tag List of tags + * @notice Used to get the reputation of a Module Factory + * @param _factoryAddress address of the Module Factory + * @return address array which has the list of securityToken's uses that module factory */ - function addTagByModuleType(uint8 _moduleType, bytes32[] _tag) external; + function getReputationByFactory(address _factoryAddress) external view returns(address[]); - /** - * @notice remove a tag for a Module Factory - * @param _moduleType Type of module. - * @param _removedTags List of tags - */ - function removeTagByModuleType(uint8 _moduleType, bytes32[] _removedTags) external; + /** + * @notice Returns all the tags related to the a module type which are valid for the given token + * @param _moduleType is the module type + * @param _securityToken is the token + * @return list of tags + * @return corresponding list of module factories + */ + function getTagsByTypeAndToken(uint8 _moduleType, address _securityToken) external view returns(bytes32[], address[]); /** - * @notice Used to get the reputation of a Module Factory - * @param _factoryAddress address of the Module Factory - * @return address array which has the list of securityToken's uses that module factory + * @notice Returns all the tags related to the a module type which are valid for the given token + * @param _moduleType is the module type + * @return list of tags + * @return corresponding list of module factories */ - function getReputationOfFactory(address _factoryAddress) external view returns(address[]); + function getTagsByType(uint8 _moduleType) external view returns(bytes32[], address[]); /** - * @notice Use to get the list of Module Factory addresses for a given module type + * @notice Returns the list of addresses of Module Factory of a particular type * @param _moduleType Type of Module - * @return address array thal contains the list of addresses of module factory contracts. + * @return address array that contains the list of addresses of module factory contracts. */ - function getModuleListOfType(uint8 _moduleType) external view returns(address[]); + function getModulesByType(uint8 _moduleType) external view returns(address[]); /** - * @notice Use to get the list of available Module factory addresses for a particular type - * @param _moduleType Type of Module - * @param _securityToken Address of securityToken + * @notice Returns the list of available Module factory addresses of a particular type for a given token. + * @param _moduleType is the module type to look for + * @param _securityToken is the address of SecurityToken * @return address array that contains the list of available addresses of module factory contracts. */ - function getAvailableModulesOfType(uint8 _moduleType, address _securityToken) external view returns (address[]); + function getModulesByTypeAndToken(uint8 _moduleType, address _securityToken) external view returns (address[]); /** * @notice Use to get the latest contract address of the regstries diff --git a/contracts/interfaces/ISecurityTokenRegistry.sol b/contracts/interfaces/ISecurityTokenRegistry.sol index 444fb5375..d7ec8f9f0 100644 --- a/contracts/interfaces/ISecurityTokenRegistry.sol +++ b/contracts/interfaces/ISecurityTokenRegistry.sol @@ -84,7 +84,7 @@ interface ISecurityTokenRegistry { /** * @notice get Protocol version */ - function getProtocolVersion() public view returns(uint8[]); + function getProtocolVersion() external view returns(uint8[]); /** * @notice Use to get the ticker list as per the owner From 02d9426de8c9445e078c5ae449c8b3439c96a796 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 21:12:43 +0100 Subject: [PATCH 37/63] Fix --- contracts/SecurityTokenRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 9c4c059ef..606a82722 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -348,7 +348,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { assert(index < tickers.length); assert(_tickerOwner(_ticker) == _owner); deleteArrayBytes32(ownerKey, index); - if (tickers.length > index) { + if (getArrayBytes32(ownerKey).length > index) { bytes32 switchedTicker = tickers[index]; set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), index); } From fefbb87d8217315a802be55c19c7478e7ee4cf14 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 22:04:37 +0100 Subject: [PATCH 38/63] Updates --- CHANGELOG.md | 8 +- migrations/2_deploy_contracts.js | 46 +++---- test/k_module_registry.js | 170 +++++++++++------------- test/t_security_token_registry_proxy.js | 2 +- test/u_module_registry_proxy.js | 8 +- 5 files changed, 113 insertions(+), 121 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 045db881c..1da8b2497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file. [__1.5.0__](https://www.npmjs.com/package/polymath-core?activeTab=readme) __15-08-18__ ## Added +* Added `getTagsByType`, `getTagsByTypeAndToken`, `getModulesByType`, `getModulesByTypeAndToken` to MR +* Removed `addTagByModuleType` & `removeTagsByModuleType` from MR * Added `getTokensByOwner` to STR * Added withholding tax to ether & erc20 dividends * Generalised MakerDAO oracle to allow different instances referencing different currencies @@ -24,10 +26,10 @@ All notable changes to this project will be documented in this file. ## 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 - -## Removed + +## Removed * Remove `swarmHash` from the `registerTicker(), addCustomTicker(), generateSecurityToken(), addCustomSecurityToken()` functions of TickerRegistry.sol and SecurityTokenRegistry.sol. #230 -* Remove `Log` prefix from all the event present in the ecosystem. +* Remove `Log` prefix from all the event present in the ecosystem. ====== diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 9b9c5eb64..97124b804 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -164,6 +164,29 @@ const functionSignatureProxyMR = { // D) Deploy the ManualApprovalTransferManagerFactory Contract (Factory used to generate the ManualApprovalTransferManager contract use // to manual approve the transfer that will overcome the other transfer restrictions) return deployer.deploy(ManualApprovalTransferManagerFactory, PolyToken, 0, 0, 0, {from: PolymathAccount}); + }).then(() => { + // H) Deploy the STVersionProxy001 Contract which contains the logic of deployment of securityToken. + return deployer.deploy(STFactory, GeneralTransferManagerFactory.address, {from: PolymathAccount}); + }).then(() => { + // K) Deploy the FeatureRegistry contract to control feature switches + return deployer.deploy(FeatureRegistry, PolymathRegistry.address, {from: PolymathAccount}); + }).then(() => { + // Assign the address into the FeatureRegistry key + return polymathRegistry.changeAddress("FeatureRegistry", FeatureRegistry.address, {from: PolymathAccount}); + }).then(() => { + // J) Deploy the SecurityTokenRegistry contract (Used to hold the deployed secuirtyToken details. It also act as the interface to deploy the SecurityToken) + return deployer.deploy(SecurityTokenRegistry, {from: PolymathAccount}) + }).then(()=> { + return deployer.deploy(SecurityTokenRegistryProxy, {from: PolymathAccount}); + }).then(() => { + let bytesProxy = web3.eth.abi.encodeFunctionCall(functionSignatureProxy, [PolymathRegistry.address, STFactory.address, initRegFee, initRegFee, PolyToken, PolymathAccount]); + SecurityTokenRegistryProxy.at(SecurityTokenRegistryProxy.address).upgradeToAndCall("1.0.0", SecurityTokenRegistry.address, bytesProxy, {from: PolymathAccount}); + }).then(() => { + // Assign the address into the SecurityTokenRegistry key + return polymathRegistry.changeAddress("SecurityTokenRegistry", SecurityTokenRegistryProxy.address, {from: PolymathAccount}); + }).then(() => { + // Update all addresses into the registry contract by calling the function updateFromregistry + return moduleRegistry.updateFromRegistry({from: PolymathAccount}); }).then(() => { // D) Register the PercentageTransferManagerFactory in the ModuleRegistry to make the factory available at the protocol level. // So any securityToken can use that factory to generate the PercentageTransferManager contract. @@ -227,29 +250,6 @@ const functionSignatureProxyMR = { // contract, Factory should comes under the verified list of factories or those factories deployed by the securityToken issuers only. // Here it gets verified because it is deployed by the third party account (Polymath Account) not with the issuer accounts. return moduleRegistry.verifyModule(ManualApprovalTransferManagerFactory.address, true, {from: PolymathAccount}); - }).then(() => { - // H) Deploy the STVersionProxy001 Contract which contains the logic of deployment of securityToken. - return deployer.deploy(STFactory, GeneralTransferManagerFactory.address, {from: PolymathAccount}); - }).then(() => { - // K) Deploy the FeatureRegistry contract to control feature switches - return deployer.deploy(FeatureRegistry, PolymathRegistry.address, {from: PolymathAccount}); - }).then(() => { - // Assign the address into the FeatureRegistry key - return polymathRegistry.changeAddress("FeatureRegistry", FeatureRegistry.address, {from: PolymathAccount}); - }).then(() => { - // J) Deploy the SecurityTokenRegistry contract (Used to hold the deployed secuirtyToken details. It also act as the interface to deploy the SecurityToken) - return deployer.deploy(SecurityTokenRegistry, {from: PolymathAccount}) - }).then(()=> { - return deployer.deploy(SecurityTokenRegistryProxy, {from: PolymathAccount}); - }).then(() => { - let bytesProxy = web3.eth.abi.encodeFunctionCall(functionSignatureProxy, [PolymathRegistry.address, STFactory.address, initRegFee, initRegFee, PolyToken, PolymathAccount]); - SecurityTokenRegistryProxy.at(SecurityTokenRegistryProxy.address).upgradeToAndCall("1.0.0", SecurityTokenRegistry.address, bytesProxy, {from: PolymathAccount}); - }).then(() => { - // Assign the address into the SecurityTokenRegistry key - return polymathRegistry.changeAddress("SecurityTokenRegistry", SecurityTokenRegistryProxy.address, {from: PolymathAccount}); - }).then(() => { - // Update all addresses into the registry contract by calling the function updateFromregistry - return moduleRegistry.updateFromRegistry({from: PolymathAccount}); }).then(() => { // M) Deploy the CappedSTOFactory (Use to generate the CappedSTO contract which will used to collect the funds ). return deployer.deploy(CappedSTOFactory, PolyToken, cappedSTOSetupCost, 0, 0, {from: PolymathAccount}) diff --git a/test/k_module_registry.js b/test/k_module_registry.js index 2cda2da9b..34007d27d 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -129,7 +129,7 @@ contract('ModuleRegistry', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); assert.notEqual( @@ -178,7 +178,7 @@ contract('ModuleRegistry', accounts => { await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); - + assert.notEqual( I_FeatureRegistry.address.valueOf(), @@ -276,11 +276,11 @@ contract('ModuleRegistry', accounts => { assert.equal(tx.logs[0].args._moduleFactory, I_GeneralTransferManagerFactory.address, "Should be the same address"); assert.equal(tx.logs[0].args._owner, account_polymath, "Should be the right owner"); - let _list = await I_MRProxied.getModuleListOfType(transferManagerKey); + let _list = await I_MRProxied.getModulesByType(transferManagerKey); assert.equal(_list.length, 1, "Length should be 1"); assert.equal(_list[0], I_GeneralTransferManagerFactory.address); - let _reputation = await I_MRProxied.getReputationOfFactory(I_GeneralTransferManagerFactory.address); + let _reputation = await I_MRProxied.getReputationByFactory(I_GeneralTransferManagerFactory.address); assert.equal(_reputation.length, 0); }); @@ -368,7 +368,7 @@ contract('ModuleRegistry', accounts => { }) describe("Test cases for the useModule function of the module registry", async() => { - + it("Deploy the securityToken", async() => { await I_PolyToken.getTokens(web3.utils.toWei("500"), account_issuer); await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("500"), {from: account_issuer}); @@ -392,30 +392,30 @@ contract('ModuleRegistry', accounts => { } assert.ok(errorThrown, message); }); - + it("Should fail to add module because custom modules not allowed", async() => { I_CappedSTOFactory2 = await CappedSTOFactory.new(I_PolyToken.address, 0, 0, 0, { from: token_owner }); - + assert.notEqual( I_CappedSTOFactory2.address.valueOf(), "0x0000000000000000000000000000000000000000", "CappedSTOFactory contract was not deployed" ); - + let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); - + assert.equal( tx.logs[0].args._moduleFactory, I_CappedSTOFactory2.address, "CappedSTOFactory is not registerd successfully" ); - + assert.equal(tx.logs[0].args._owner, token_owner); - + startTime = latestTime() + duration.seconds(5000); endTime = startTime + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); - + let errorThrown = false; try { tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); @@ -426,20 +426,20 @@ contract('ModuleRegistry', accounts => { } assert.ok(errorThrown, message); }); - + it("Should switch customModulesAllowed to true", async() => { assert.equal(false, await I_FeatureRegistry.getFeatureStatus.call("customModulesAllowed"), "Custom modules should be dissabled by default."); let tx = await I_FeatureRegistry.setFeatureStatus("customModulesAllowed", true, { from: account_polymath }); assert.equal(true, await I_FeatureRegistry.getFeatureStatus.call("customModulesAllowed"), "Custom modules should be switched to true."); }); - + it("Should successfully add module because custom modules switched on", async() => { startTime = latestTime() + duration.seconds(5000); endTime = startTime + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); - + let tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); - + assert.equal(tx.logs[2].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal( web3.utils.toAscii(tx.logs[2].args._name) @@ -447,10 +447,10 @@ contract('ModuleRegistry', accounts => { "CappedSTO", "CappedSTOFactory module was not added" ); - let _reputation = await I_MRProxied.getReputationOfFactory.call(I_CappedSTOFactory2.address); + let _reputation = await I_MRProxied.getReputationByFactory.call(I_CappedSTOFactory2.address); assert.equal(_reputation.length, 1); }); - + it("Should successfully add verified module", async() => { I_GeneralPermissionManagerFactory = await GeneralPermissionManagerFactory.new(I_PolyToken.address, 0, 0, 0, {from: account_polymath}); await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, {from: account_polymath}); @@ -461,7 +461,7 @@ contract('ModuleRegistry', accounts => { it("Should failed in adding the TestSTOFactory module because not compatible with the current protocol version --lower", async() => { I_TestSTOFactory = await TestSTOFactory.new(I_PolyToken.address, 0, 0, 0, {from: account_polymath}); - await I_MRProxied.registerModule(I_TestSTOFactory.address, {from: token_owner}); + await I_MRProxied.registerModule(I_TestSTOFactory.address, {from: account_polymath}); await I_MRProxied.verifyModule(I_TestSTOFactory.address, true, {from: account_polymath}); // Taking the snapshot the revert the changes from here let id = await takeSnapshot(); @@ -513,59 +513,49 @@ contract('ModuleRegistry', accounts => { }); - describe("Test cases for the tag functions", async() => { - - it("Should fail in adding the tag. Because msg.sender is not the owner", async() => { - let errorThrown = false; - try { - await I_MRProxied.addTagByModuleType(3,["Non-Refundable","Capped","ETH","POLY"],{from: account_temp}); - } catch(error) { - console.log(` tx revert -> msg.sender should be account_polymath`.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - }); - - it("Should successfully add the tag", async() => { - await I_MRProxied.addTagByModuleType(3,["Non-Refundable","Capped","ETH","POLY"],{from: account_polymath}); - let tags = await I_MRProxied.getTagByModuleType.call(3); - assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ''),"Non-Refundable"); - }); - - it("Should fail in removing the tag from the list", async() => { - let errorThrown = false; - try { - await I_MRProxied.removeTagByModuleType(3,["Capped", "ETH"], {from: account_investor1}); - } catch(error) { - console.log(` tx revert -> msg.sender should be account_polymath`.grey); - errorThrown = true; - ensureException(error); - } - assert.ok(errorThrown, message); - }); - - it("Should remove the tag from the list", async() => { - await I_MRProxied.removeTagByModuleType(3,["Capped", "ETH"], {from:account_polymath}); - let tags = await I_MRProxied.getTagByModuleType.call(3); - assert.equal(web3.utils.toAscii(tags[1]).replace(/\u0000/g, ''),"POLY"); - }); - }); - - describe("Test case for the getAvailableModulesOfType()", async() => { + describe("Test case for the getModulesByTypeAndToken()", async() => { it("Should get the list of available modules when the customModulesAllowed", async() => { - let _list = await I_MRProxied.getAvailableModulesOfType.call(3, I_SecurityToken.address); + let _list = await I_MRProxied.getModulesByTypeAndToken.call(3, I_SecurityToken.address); assert.equal(_list[0], I_CappedSTOFactory2.address); }) it("Should get the list of available modules when the customModulesAllowed is not allowed", async() => { await I_FeatureRegistry.setFeatureStatus("customModulesAllowed", false, { from: account_polymath }); - let _list = await I_MRProxied.getAvailableModulesOfType.call(3, I_SecurityToken.address); + let _list = await I_MRProxied.getModulesByTypeAndToken.call(3, I_SecurityToken.address); assert.equal(_list.length, 0); }) }) + describe("Test cases for getters", async() => { + + it("Check getter - ", async() => { + console.log("getModulesByType:") + for (let i = 0; i < 5; i++) { + let _list = await I_MRProxied.getModulesByType.call(i); + console.log("Type: " + i + ":" + _list); + } + console.log("getModulesByTypeAndToken:") + for (let i = 0; i < 5; i++) { + let _list = await I_MRProxied.getModulesByTypeAndToken.call(i, I_SecurityToken.address); + console.log("Type: " + i + ":" + _list); + } + console.log("getTagsByType:") + for (let i = 0; i < 5; i++) { + let _list = await I_MRProxied.getTagsByType.call(i); + console.log("Type: " + i + ":" + _list[1]); + console.log("Type: " + i + ":" + _list[0].map(x => web3.utils.toAscii(x))); + } + console.log("getTagsByTypeAndToken:") + for (let i = 0; i < 5; i++) { + let _list = await I_MRProxied.getTagsByTypeAndToken.call(i, I_SecurityToken.address); + console.log("Type: " + i + ":" + _list[1]); + console.log("Type: " + i + ":" + _list[0].map(x => web3.utils.toAscii(x))); + } + }) + + }); + describe("Test cases for removeModule()", async() => { it("Should fail if msg.sender not curator or owner", async() => { @@ -579,59 +569,59 @@ contract('ModuleRegistry', accounts => { } assert.ok(errorThrown, message); }); - + it("Should successfully remove module and delete data if msg.sender is curator", async() => { let snap = await takeSnapshot(); - - let sto1 = (await I_MRProxied.getModuleListOfType.call(3))[0]; - let sto2 = (await I_MRProxied.getModuleListOfType.call(3))[1]; - + + let sto1 = (await I_MRProxied.getModulesByType.call(3))[0]; + let sto2 = (await I_MRProxied.getModulesByType.call(3))[1]; + assert.equal(sto1,I_CappedSTOFactory1.address); assert.equal(sto2,I_CappedSTOFactory2.address); - assert.equal((await I_MRProxied.getModuleListOfType.call(3)).length, 3); - + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 3); + let tx = await I_MRProxied.removeModule(sto1, { from: account_polymath }); - + assert.equal(tx.logs[0].args._moduleFactory, sto1, "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.getModuleListOfType.call(3))[1]; - + + let sto2_end = (await I_MRProxied.getModulesByType.call(3))[1]; + // re-ordering assert.equal(sto2_end,sto2); // delete related data assert.equal(await I_MRProxied.getUintValues.call(web3.utils.soliditySha3("registry", sto1)), 0); - assert.equal(await I_MRProxied.getReputationOfFactory.call(sto1), 0); - assert.equal((await I_MRProxied.getModuleListOfType.call(3)).length, 2); + 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); - + await revertToSnapshot(snap); }); - + it("Should successfully remove module and delete data if msg.sender is owner", async() => { - let sto1 = (await I_MRProxied.getModuleListOfType.call(3))[0]; - let sto2 = (await I_MRProxied.getModuleListOfType.call(3))[1]; - + let sto1 = (await I_MRProxied.getModulesByType.call(3))[0]; + let sto2 = (await I_MRProxied.getModulesByType.call(3))[1]; + assert.equal(sto1,I_CappedSTOFactory1.address); assert.equal(sto2,I_CappedSTOFactory2.address); - assert.equal((await I_MRProxied.getModuleListOfType.call(3)).length, 3); - + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 3); + let tx = await I_MRProxied.removeModule(sto2, { from: token_owner }); - + assert.equal(tx.logs[0].args._moduleFactory, sto2, "Event is not properly emitted for _moduleFactory"); assert.equal(tx.logs[0].args._decisionMaker, token_owner, "Event is not properly emitted for _decisionMaker"); - - let sto1_end = (await I_MRProxied.getModuleListOfType.call(3))[0]; - + + let sto1_end = (await I_MRProxied.getModulesByType.call(3))[0]; + // re-ordering assert.equal(sto1_end,sto1); // delete related data assert.equal(await I_MRProxied.getUintValues.call(web3.utils.soliditySha3("registry", sto2)), 0); - assert.equal(await I_MRProxied.getReputationOfFactory.call(sto2), 0); - assert.equal((await I_MRProxied.getModuleListOfType.call(3)).length, 2); + assert.equal(await I_MRProxied.getReputationByFactory.call(sto2), 0); + assert.equal((await I_MRProxied.getModulesByType.call(3)).length, 2); assert.equal(await I_MRProxied.getBoolValues.call(web3.utils.soliditySha3("verified", sto2)), false); }); - + it("Should fail if module already removed", async() => { let errorThrown = false; try { @@ -643,7 +633,7 @@ contract('ModuleRegistry', accounts => { } assert.ok(errorThrown, message); }); - + }); describe("Test cases for IRegistry functionality", async() => { @@ -703,4 +693,4 @@ contract('ModuleRegistry', accounts => { }); }); -}); \ No newline at end of file +}); diff --git a/test/t_security_token_registry_proxy.js b/test/t_security_token_registry_proxy.js index dc258f670..cb313cb9d 100644 --- a/test/t_security_token_registry_proxy.js +++ b/test/t_security_token_registry_proxy.js @@ -83,7 +83,7 @@ contract ("SecurityTokenRegistryProxy", accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); diff --git a/test/u_module_registry_proxy.js b/test/u_module_registry_proxy.js index 82583d594..f79731b8c 100644 --- a/test/u_module_registry_proxy.js +++ b/test/u_module_registry_proxy.js @@ -85,7 +85,7 @@ contract ("ModuleRegistryProxy", accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -196,7 +196,7 @@ contract ("ModuleRegistryProxy", accounts => { it("Should add the tags successfuly", async() => { await I_MRProxied.addTagByModuleType(3,["Non-Refundable","Capped","ETH","POLY"],{from: account_polymath}); - let tags = await I_MRProxied.getTagByModuleType.call(3); + let tags = await I_MRProxied.getTagsByType.call(3); assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ''),"Non-Refundable"); }) }) @@ -288,7 +288,7 @@ contract ("ModuleRegistryProxy", accounts => { describe("Execute functionality of the implementation contract on the earlier storage", async() => { it("Should get the previous data", async() => { - let _data = await I_MRProxied.getTagByModuleType.call(3); + let _data = await I_MRProxied.getTagsByType.call(3); assert.equal(web3.utils.toUtf8(_data[0]), "Non-Refundable"); assert.equal(web3.utils.toUtf8(_data[1]), "Capped"); assert.equal(web3.utils.toUtf8(_data[2]), "ETH"); @@ -296,7 +296,7 @@ contract ("ModuleRegistryProxy", accounts => { it("Should alter the old storage", async() => { await I_MRProxied.addMoreTags(3, ["DAI", "USDTiered"], {from: account_polymath}); - let _data = await I_MRProxied.getTagByModuleType.call(3); + let _data = await I_MRProxied.getTagsByType.call(3); assert.equal(_data.length, 6, "Should give the updated length"); }); }) From 626083a563c3f83b616f18f49d36a91ea27af7ac Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 22:35:28 +0100 Subject: [PATCH 39/63] More fixes for tests --- contracts/ModuleRegistry.sol | 5 +++- contracts/mocks/MockModuleRegistry.sol | 19 ++++++++++++++ contracts/mocks/ModuleRegistryMock.sol | 18 ------------- test/b_capped_sto.js | 4 +-- test/i_Issuance.js | 6 ++--- test/o_security_token.js | 4 +-- test/u_module_registry_proxy.js | 36 ++++++++++---------------- 7 files changed, 44 insertions(+), 48 deletions(-) create mode 100644 contracts/mocks/MockModuleRegistry.sol delete mode 100644 contracts/mocks/ModuleRegistryMock.sol diff --git a/contracts/ModuleRegistry.sol b/contracts/ModuleRegistry.sol index b745e9395..f0249e2fd 100644 --- a/contracts/ModuleRegistry.sol +++ b/contracts/ModuleRegistry.sol @@ -133,7 +133,7 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { } } - function _isCompatibleModule(address _moduleFactory, address _securityToken) internal returns(bool) { + function _isCompatibleModule(address _moduleFactory, address _securityToken) internal view returns(bool) { uint8[] memory _latestVersion = ISecurityToken(_securityToken).getVersion(); uint8[] memory _lowerBound = IModuleFactory(_moduleFactory).getLowerSTVersionBounds(); uint8[] memory _upperBound = IModuleFactory(_moduleFactory).getUpperSTVersionBounds(); @@ -148,6 +148,9 @@ contract ModuleRegistry is IModuleRegistry, EternalStorage { */ function registerModule(address _moduleFactory) external whenNotPausedOrOwner { if (IFeatureRegistry(getAddress(Encoder.getKey('featureRegistry'))).getFeatureStatus("customModulesAllowed")) { + require(msg.sender == IOwnable(_moduleFactory).owner() || msg.sender == getAddress(Encoder.getKey('owner')), + "msg.sender must be the Module Factory owner or registry curator"); + } else { require(msg.sender == getAddress(Encoder.getKey("owner")), "Only owner allowed to register modules"); } require(getUint(Encoder.getKey('registry', _moduleFactory)) == 0, "Module factory should not be pre-registered"); diff --git a/contracts/mocks/MockModuleRegistry.sol b/contracts/mocks/MockModuleRegistry.sol new file mode 100644 index 000000000..23af59d58 --- /dev/null +++ b/contracts/mocks/MockModuleRegistry.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.4.24; + +import "../ModuleRegistry.sol"; + +/** + * @title Registry contract for issuers to register their security tokens + */ +contract MockModuleRegistry is ModuleRegistry { + + /// @notice It is dummy functionality + /// Alert! Alert! Do not use it for the mainnet release + function addMoreReputation(address _moduleFactory, address[] _tokens) public onlyOwner { + for (uint8 i = 0; i < _tokens.length; i++) { + pushArray(Encoder.getKey('reputation', _moduleFactory), _tokens[i]); + } + } + + +} diff --git a/contracts/mocks/ModuleRegistryMock.sol b/contracts/mocks/ModuleRegistryMock.sol deleted file mode 100644 index 18551dd20..000000000 --- a/contracts/mocks/ModuleRegistryMock.sol +++ /dev/null @@ -1,18 +0,0 @@ -pragma solidity ^0.4.24; - -import "../ModuleRegistry.sol"; - -/** - * @title Registry contract for issuers to register their security tokens - */ -contract ModuleRegistryMock is ModuleRegistry { - - /// @notice It is dummy functionality - /// Alert! Alert! Do not use it for the mainnet release - function addMoreTags(uint8 _moduleType, bytes32[] _tag) public onlyOwner { - for (uint8 i = 0; i < _tag.length; i++) { - pushArray(Encoder.getKey('availableTags', uint256(_moduleType)), _tag[i]); - } - } - -} \ No newline at end of file diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 36f5bd41e..553544d48 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -139,7 +139,7 @@ contract('CappedSTO', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -188,7 +188,7 @@ contract('CappedSTO', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: token_owner }); + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); // Step 8: Deploy the STFactory contract diff --git a/test/i_Issuance.js b/test/i_Issuance.js index d2691674e..63884d2d3 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -120,14 +120,14 @@ contract('Issuance', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); let bytesMRProxy = encodeProxyCall(MRProxyParameters, [I_PolymathRegistry.address, account_polymath]); await I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesMRProxy, {from: account_polymath}); I_MRProxied = await ModuleRegistry.at(I_ModuleRegistryProxy.address); - + // STEP 4: Deploy the GeneralTransferManagerFactory I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, {from:account_polymath}); @@ -169,7 +169,7 @@ contract('Issuance', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: token_owner }); + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); // Step 8: Deploy the STFactory contract diff --git a/test/o_security_token.js b/test/o_security_token.js index 8e4223f7d..a09dae907 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -139,7 +139,7 @@ contract('SecurityToken', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -188,7 +188,7 @@ contract('SecurityToken', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: token_owner }); + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); // Step 6: Deploy the STFactory contract diff --git a/test/u_module_registry_proxy.js b/test/u_module_registry_proxy.js index f79731b8c..b6fcc5db5 100644 --- a/test/u_module_registry_proxy.js +++ b/test/u_module_registry_proxy.js @@ -5,7 +5,7 @@ const SecurityTokenRegistry = artifacts.require("./SecurityTokenRegistry.sol"); const SecurityTokenRegistryProxy = artifacts.require("./SecurityTokenRegistryProxy.sol"); const GeneralTransferManagerFactory = artifacts.require("./GeneralTransferManagerFactory.sol"); const GeneralPermissionManagerFactory = artifacts.require('./GeneralPermissionManagerFactory.sol'); -const ModuleRegistryMock = artifacts.require("./ModuleRegistryMock.sol"); +const MockModuleRegistry = artifacts.require("./MockModuleRegistry.sol"); const OwnedUpgradeabilityProxy = artifacts.require('./OwnedUpgradeabilityProxy.sol'); const PolymathRegistry = artifacts.require('./PolymathRegistry.sol') const ModuleRegistry = artifacts.require('./ModuleRegistry.sol') @@ -26,7 +26,7 @@ contract ("ModuleRegistryProxy", accounts => { let I_SecurityTokenRegistryProxy; let I_GeneralTransferManagerFactory; let I_GeneralPermissionManagerfactory; - let I_ModuleRegistryMock; + let I_MockModuleRegistry; let I_STFactory; let I_PolymathRegistry; let I_ModuleRegistryProxy; @@ -160,7 +160,6 @@ contract ("ModuleRegistryProxy", accounts => { // Step 3: Deploy the STFactory contract - I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); assert.notEqual( @@ -194,20 +193,15 @@ contract ("ModuleRegistryProxy", accounts => { }); - it("Should add the tags successfuly", async() => { - await I_MRProxied.addTagByModuleType(3,["Non-Refundable","Capped","ETH","POLY"],{from: account_polymath}); - let tags = await I_MRProxied.getTagsByType.call(3); - assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ''),"Non-Refundable"); - }) }) describe("Upgrade the imlplementation address", async() => { it("Should upgrade the version and implementation address -- fail bad owner", async() => { let errorThrown = false; - I_ModuleRegistryMock = await ModuleRegistryMock.new({from: account_polymath}); + I_MockModuleRegistry = await MockModuleRegistry.new({from: account_polymath}); try { - await I_ModuleRegistryProxy.upgradeTo("1.1.0", I_ModuleRegistryMock.address, {from: account_temp}); + await I_ModuleRegistryProxy.upgradeTo("1.1.0", I_MockModuleRegistry.address, {from: account_temp}); } catch(error) { console.log(` tx -> revert bad owner of the proxy contract`); errorThrown = true; @@ -255,7 +249,7 @@ contract ("ModuleRegistryProxy", accounts => { it("Should upgrade the version and implementation address -- same version as previous is not allowed", async() => { let errorThrown = false; try { - await I_ModuleRegistryProxy.upgradeTo("1.0.0", I_ModuleRegistryMock.address, {from: account_polymath}); + await I_ModuleRegistryProxy.upgradeTo("1.0.0", I_MockModuleRegistry.address, {from: account_polymath}); } catch(error) { console.log(` tx -> revert same version as previous is not allowed`); errorThrown = true; @@ -267,7 +261,7 @@ contract ("ModuleRegistryProxy", accounts => { it("Should upgrade the version and implementation address -- empty version string is not allowed", async() => { let errorThrown = false; try { - await I_ModuleRegistryProxy.upgradeTo("", I_ModuleRegistryMock.address, {from: account_polymath}); + await I_ModuleRegistryProxy.upgradeTo("", I_MockModuleRegistry.address, {from: account_polymath}); } catch(error) { console.log(` tx -> revert empty version string is not allowed`); errorThrown = true; @@ -277,27 +271,25 @@ contract ("ModuleRegistryProxy", accounts => { }); it("Should upgrade the version and the implementation address successfully", async() => { - await I_ModuleRegistryProxy.upgradeTo("1.1.0", I_ModuleRegistryMock.address, {from: account_polymath}); + await I_ModuleRegistryProxy.upgradeTo("1.1.0", I_MockModuleRegistry.address, {from: account_polymath}); let c = OwnedUpgradeabilityProxy.at(I_ModuleRegistryProxy.address); assert.equal((web3.utils.toAscii(await readStorage(c.address, 11)).replace(/\u0000/g, '')).replace(/\n/, ''), "1.1.0", "Version mis-match"); - assert.equal(await readStorage(c.address, 12), I_ModuleRegistryMock.address, "Implemnted address is not matched"); - I_MRProxied = await ModuleRegistryMock.at(I_ModuleRegistryProxy.address); + assert.equal(await readStorage(c.address, 12), I_MockModuleRegistry.address, "Implemnted address is not matched"); + I_MRProxied = await MockModuleRegistry.at(I_ModuleRegistryProxy.address); }); }); describe("Execute functionality of the implementation contract on the earlier storage", async() => { it("Should get the previous data", async() => { - let _data = await I_MRProxied.getTagsByType.call(3); - assert.equal(web3.utils.toUtf8(_data[0]), "Non-Refundable"); - assert.equal(web3.utils.toUtf8(_data[1]), "Capped"); - assert.equal(web3.utils.toUtf8(_data[2]), "ETH"); + let _data = await I_MRProxied.getReputationByFactory.call(I_GeneralTransferManagerFactory.address); + assert.equal(_data.length, 0, "Should give the original length"); }); it("Should alter the old storage", async() => { - await I_MRProxied.addMoreTags(3, ["DAI", "USDTiered"], {from: account_polymath}); - let _data = await I_MRProxied.getTagsByType.call(3); - assert.equal(_data.length, 6, "Should give the updated length"); + await I_MRProxied.addMoreReputation(I_GeneralTransferManagerFactory.address, [account_polymath, account_temp], {from: account_polymath}); + let _data = await I_MRProxied.getReputationByFactory.call(I_GeneralTransferManagerFactory.address); + assert.equal(_data.length, 2, "Should give the updated length"); }); }) From c993c5f5c505fc38fa874679523022d2d57ccf21 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 22:50:08 +0100 Subject: [PATCH 40/63] Fix every test case (sigh) --- test/b_capped_sto.js | 31 +++++++------- test/c_checkpoints.js | 22 +++++----- test/d_count_transfer_manager.js | 43 ++++++++++--------- test/e_erc20_dividends.js | 38 ++++++++--------- test/f_ether_dividends.js | 48 +++++++++++----------- test/g_general_permission_manager.js | 38 ++++++++--------- test/h_general_transfer_manager.js | 40 +++++++++--------- test/i_Issuance.js | 28 ++++++------- test/j_manual_approval_transfer_manager.js | 46 ++++++++++----------- test/l_percentage_transfer_manager.js | 40 +++++++++--------- test/m_presale_sto.js | 30 +++++++------- test/n_security_token_registry.js | 24 +++++------ test/o_security_token.js | 24 +++++------ test/p_usd_tiered_sto.js | 31 +++++++------- test/q_usd_tiered_sto_sim.js | 33 +++++++-------- test/r_concurrent_STO.js | 43 +++++++++---------- test/s_v130_to_v140_upgrade.js | 26 ++++++------ test/t_security_token_registry_proxy.js | 8 ++-- test/u_module_registry_proxy.js | 9 ++-- 19 files changed, 303 insertions(+), 299 deletions(-) diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 553544d48..11a797933 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -177,20 +177,6 @@ contract('CappedSTO', accounts => { "CappedSTOFactory contract was not deployed" ); - // STEP 7: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); - // Step 8: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -224,6 +210,23 @@ contract('CappedSTO', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 7: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + console.log(await I_MRProxied.owner()); + console.log(account_polymath); + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); + + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index 0f317765e..d40996a66 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -105,7 +105,7 @@ contract('Checkpoints', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -133,16 +133,6 @@ contract('Checkpoints', accounts => { "GeneralDelegateManagerFactory contract was not deployed" ); - // STEP 6: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - // Step 7: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -176,6 +166,16 @@ contract('Checkpoints', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 6: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 309e4bdaa..4b65e249a 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -117,9 +117,9 @@ contract('CountTransferManager', accounts => { "0x0000000000000000000000000000000000000000", "FeatureRegistry contract was not deployed", ); - + // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -164,24 +164,6 @@ contract('CountTransferManager', accounts => { "CountTransferManagerFactory contract was not deployed" ); - // STEP 8: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the CountTransferManagerFactory - await I_MRProxied.registerModule(I_CountTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_CountTransferManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the Paid CountTransferManagerFactory - await I_MRProxied.registerModule(P_CountTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(P_CountTransferManagerFactory.address, true, { from: account_polymath }); - // Step 9: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address); @@ -207,8 +189,8 @@ contract('CountTransferManager', accounts => { I_SecurityTokenRegistryProxy = await SecurityTokenRegistryProxy.new({from: account_polymath}); let bytesProxy = encodeProxyCall(STRProxyParameters, [I_PolymathRegistry.address, I_STFactory.address, initRegFee, initRegFee, I_PolyToken.address, account_polymath]); await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); - I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); - + I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); + // Step 12: update the registries addresses from the PolymathRegistry contract await I_PolymathRegistry.changeAddress("PolyToken", I_PolyToken.address, {from: account_polymath}) await I_PolymathRegistry.changeAddress("ModuleRegistry", I_ModuleRegistryProxy.address, {from: account_polymath}); @@ -216,6 +198,23 @@ contract('CountTransferManager', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 8: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the CountTransferManagerFactory + await I_MRProxied.registerModule(I_CountTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_CountTransferManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the Paid CountTransferManagerFactory + await I_MRProxied.registerModule(P_CountTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(P_CountTransferManagerFactory.address, true, { from: account_polymath }); // Printing all the contract addresses console.log(` diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 395afbec2..82125d688 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -113,7 +113,7 @@ contract('ERC20DividendCheckpoint', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -157,24 +157,6 @@ contract('ERC20DividendCheckpoint', accounts => { "ERC20DividendCheckpointFactory contract was not deployed" ); - // STEP 8: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the ERC20DividendCheckpointFactory - await I_MRProxied.registerModule(I_ERC20DividendCheckpointFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_ERC20DividendCheckpointFactory.address, true, { from: account_polymath }); - - // (C) : Register the Paid ERC20DividendCheckpointFactory - await I_MRProxied.registerModule(P_ERC20DividendCheckpointFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(P_ERC20DividendCheckpointFactory.address, true, { from: account_polymath }); - // Step 9: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address); @@ -208,6 +190,24 @@ contract('ERC20DividendCheckpoint', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 8: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the ERC20DividendCheckpointFactory + await I_MRProxied.registerModule(I_ERC20DividendCheckpointFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_ERC20DividendCheckpointFactory.address, true, { from: account_polymath }); + + // (C) : Register the Paid ERC20DividendCheckpointFactory + await I_MRProxied.registerModule(P_ERC20DividendCheckpointFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(P_ERC20DividendCheckpointFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 00a8852a2..0e7468075 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -113,7 +113,7 @@ contract('EtherDividendCheckpoint', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -157,24 +157,6 @@ contract('EtherDividendCheckpoint', accounts => { "EtherDividendCheckpointFactory contract was not deployed" ); - // STEP 5: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the EtherDividendCheckpointFactory - await I_MRProxied.registerModule(I_EtherDividendCheckpointFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_EtherDividendCheckpointFactory.address, true, { from: account_polymath }); - - // (C) : Register the Paid EtherDividendCheckpointFactory - await I_MRProxied.registerModule(P_EtherDividendCheckpointFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(P_EtherDividendCheckpointFactory.address, true, { from: account_polymath }); - // Step 6: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -184,23 +166,23 @@ contract('EtherDividendCheckpoint', accounts => { "0x0000000000000000000000000000000000000000", "STFactory contract was not deployed", ); - + // Step 7: Deploy the SecurityTokenRegistry contract - + I_SecurityTokenRegistry = await SecurityTokenRegistry.new({from: account_polymath }); - + assert.notEqual( I_SecurityTokenRegistry.address.valueOf(), "0x0000000000000000000000000000000000000000", "SecurityTokenRegistry contract was not deployed", ); - + // Step 8: Deploy the proxy and attach the implementation contract to it. I_SecurityTokenRegistryProxy = await SecurityTokenRegistryProxy.new({from: account_polymath}); let bytesProxy = encodeProxyCall(STRProxyParameters, [I_PolymathRegistry.address, I_STFactory.address, initRegFee, initRegFee, I_PolyToken.address, account_polymath]); await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); - + // Step 9: update the registries addresses from the PolymathRegistry contract await I_PolymathRegistry.changeAddress("PolyToken", I_PolyToken.address, {from: account_polymath}) await I_PolymathRegistry.changeAddress("ModuleRegistry", I_ModuleRegistryProxy.address, {from: account_polymath}); @@ -208,6 +190,24 @@ contract('EtherDividendCheckpoint', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the EtherDividendCheckpointFactory + await I_MRProxied.registerModule(I_EtherDividendCheckpointFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_EtherDividendCheckpointFactory.address, true, { from: account_polymath }); + + // (C) : Register the Paid EtherDividendCheckpointFactory + await I_MRProxied.registerModule(P_EtherDividendCheckpointFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(P_EtherDividendCheckpointFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index 118dca77f..6e483d203 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -123,7 +123,7 @@ contract('GeneralPermissionManager', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -171,24 +171,6 @@ contract('GeneralPermissionManager', accounts => { "DummySTOFactory contract was not deployed" ); - // STEP 8: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the Paid GeneralDelegateManagerFactory - await I_MRProxied.registerModule(P_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(P_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); - // Step 8: Deploy the STFactory contract @@ -223,6 +205,24 @@ contract('GeneralPermissionManager', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 8: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the Paid GeneralDelegateManagerFactory + await I_MRProxied.registerModule(P_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(P_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index cda17f0cb..190ab54ad 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -124,7 +124,7 @@ contract('GeneralTransferManager', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -163,20 +163,6 @@ contract('GeneralTransferManager', accounts => { "DummySTOFactory contract was not deployed" ); - // STEP 5: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); - // Step 8: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -186,23 +172,23 @@ contract('GeneralTransferManager', accounts => { "0x0000000000000000000000000000000000000000", "STFactory contract was not deployed", ); - + // Step 9: Deploy the SecurityTokenRegistry contract - + I_SecurityTokenRegistry = await SecurityTokenRegistry.new({from: account_polymath }); - + assert.notEqual( I_SecurityTokenRegistry.address.valueOf(), "0x0000000000000000000000000000000000000000", "SecurityTokenRegistry contract was not deployed", ); - + // Step 10: Deploy the proxy and attach the implementation contract to it. I_SecurityTokenRegistryProxy = await SecurityTokenRegistryProxy.new({from: account_polymath}); let bytesProxy = encodeProxyCall(STRProxyParameters, [I_PolymathRegistry.address, I_STFactory.address, initRegFee, initRegFee, I_PolyToken.address, account_polymath]); await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); I_STRProxied = await SecurityTokenRegistry.at(I_SecurityTokenRegistryProxy.address); - + // Step 11: update the registries addresses from the PolymathRegistry contract await I_PolymathRegistry.changeAddress("PolyToken", I_PolyToken.address, {from: account_polymath}) await I_PolymathRegistry.changeAddress("ModuleRegistry", I_ModuleRegistryProxy.address, {from: account_polymath}); @@ -210,6 +196,20 @@ contract('GeneralTransferManager', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/i_Issuance.js b/test/i_Issuance.js index 63884d2d3..4cfe448d3 100644 --- a/test/i_Issuance.js +++ b/test/i_Issuance.js @@ -158,20 +158,6 @@ contract('Issuance', accounts => { "CappedSTOFactory contract was not deployed" ); - // STEP 7: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); - // Step 8: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -205,6 +191,20 @@ contract('Issuance', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 7: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index b9517b8c9..78953fa24 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -117,7 +117,7 @@ contract('ManualApprovalTransferManager', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -169,28 +169,6 @@ contract('ManualApprovalTransferManager', accounts => { "CountTransferManagerFactory contract was not deployed" ); - // STEP 9: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the ManualApprovalTransferManagerFactory - await I_MRProxied.registerModule(I_ManualApprovalTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_ManualApprovalTransferManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the ManualApprovalTransferManagerFactory - await I_MRProxied.registerModule(P_ManualApprovalTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(P_ManualApprovalTransferManagerFactory.address, true, { from: account_polymath }); - - // (D) : Register the CountTransferManagerFactory - await I_MRProxied.registerModule(I_CountTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_CountTransferManagerFactory.address, true, { from: account_polymath }); - // Step 10: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -224,6 +202,28 @@ contract('ManualApprovalTransferManager', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 9: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the ManualApprovalTransferManagerFactory + await I_MRProxied.registerModule(I_ManualApprovalTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_ManualApprovalTransferManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the ManualApprovalTransferManagerFactory + await I_MRProxied.registerModule(P_ManualApprovalTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(P_ManualApprovalTransferManagerFactory.address, true, { from: account_polymath }); + + // (D) : Register the CountTransferManagerFactory + await I_MRProxied.registerModule(I_CountTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_CountTransferManagerFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 23ec5b8d4..92504c4c2 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -122,14 +122,14 @@ contract('PercentageTransferManager', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); let bytesMRProxy = encodeProxyCall(MRProxyParameters, [I_PolymathRegistry.address, account_polymath]); await I_ModuleRegistryProxy.upgradeToAndCall("1.0.0", I_ModuleRegistry.address, bytesMRProxy, {from: account_polymath}); I_MRProxied = await ModuleRegistry.at(I_ModuleRegistryProxy.address); - + // STEP 4(a): Deploy the GeneralTransferManagerFactory I_GeneralTransferManagerFactory = await GeneralTransferManagerFactory.new(I_PolyToken.address, 0, 0, 0, {from:account_polymath}); @@ -167,24 +167,6 @@ contract('PercentageTransferManager', accounts => { ); - // STEP 5: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the PercentageTransferManagerFactory - await I_MRProxied.registerModule(I_PercentageTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_PercentageTransferManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the Paid PercentageTransferManagerFactory - await I_MRProxied.registerModule(P_PercentageTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(P_PercentageTransferManagerFactory.address, true, { from: account_polymath }); - // Step 6: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -218,6 +200,24 @@ contract('PercentageTransferManager', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the PercentageTransferManagerFactory + await I_MRProxied.registerModule(I_PercentageTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_PercentageTransferManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the Paid PercentageTransferManagerFactory + await I_MRProxied.registerModule(P_PercentageTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(P_PercentageTransferManagerFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index c14156f2d..ff3d8ffdf 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -112,7 +112,7 @@ contract('PreSaleSTO', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -150,20 +150,6 @@ contract('PreSaleSTO', accounts => { "PreSaleSTOFactory contract was not deployed" ); - // STEP 5: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: token_owner }); - await I_MRProxied.verifyModule(I_PreSaleSTOFactory.address, true, { from: account_polymath }); - // Step 8: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -197,6 +183,20 @@ contract('PreSaleSTO', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: token_owner }); + await I_MRProxied.verifyModule(I_PreSaleSTOFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index a53378c8b..196186646 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -131,7 +131,7 @@ contract('SecurityTokenRegistry', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -160,16 +160,6 @@ contract('SecurityTokenRegistry', accounts => { ); - // STEP 4: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - // Step 6: Deploy the STversionProxy contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -203,7 +193,7 @@ contract('SecurityTokenRegistry', accounts => { "SecurityTokenRegistry contract was not deployed", ); - // Step 9 (a): Deploy the proxy + // Step 9 (a): Deploy the proxy I_SecurityTokenRegistryProxy = await SecurityTokenRegistryProxy.new({from: account_polymath}); let bytesProxy = encodeProxyCall(STRProxyParameters, [I_PolymathRegistry.address, I_STFactory.address, initRegFee, initRegFee, I_PolyToken.address, account_polymath]); await I_SecurityTokenRegistryProxy.upgradeToAndCall("1.0.0", I_SecurityTokenRegistry.address, bytesProxy, {from: account_polymath}); @@ -230,6 +220,16 @@ contract('SecurityTokenRegistry', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 4: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + console.log(` --------------------- Polymath Network Smart Contracts: --------------------- PolymathRegistry: ${PolymathRegistry.address} diff --git a/test/o_security_token.js b/test/o_security_token.js index a09dae907..255948627 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -179,18 +179,6 @@ contract('SecurityToken', accounts => { // STEP 5: Register the Modules with the ModuleRegistry contract - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); - // Step 6: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); @@ -223,6 +211,18 @@ contract('SecurityToken', accounts => { await I_PolymathRegistry.changeAddress("FeatureRegistry", I_FeatureRegistry.address, {from: account_polymath}); await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 0f0fbd6e7..4be82a435 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -225,7 +225,7 @@ contract('USDTieredSTO', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from: POLYMATH}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from: POLYMATH}); @@ -266,20 +266,6 @@ contract('USDTieredSTO', accounts => { "USDTieredSTOFactory contract was not deployed" ); - // STEP 7: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: POLYMATH }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: ISSUER }); - await I_MRProxied.verifyModule(I_USDTieredSTOFactory.address, true, { from: POLYMATH }); - // Step 8: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : POLYMATH }); @@ -313,6 +299,21 @@ contract('USDTieredSTO', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: POLYMATH}); await I_MRProxied.updateFromRegistry({from: POLYMATH}); + + // STEP 7: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: POLYMATH }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: ISSUER }); + await I_MRProxied.verifyModule(I_USDTieredSTOFactory.address, true, { from: POLYMATH }); + // 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 diff --git a/test/q_usd_tiered_sto_sim.js b/test/q_usd_tiered_sto_sim.js index f8ce2c1ea..965479485 100644 --- a/test/q_usd_tiered_sto_sim.js +++ b/test/q_usd_tiered_sto_sim.js @@ -195,7 +195,7 @@ contract('USDTieredSTO Sim', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from: POLYMATH}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from: POLYMATH}); @@ -228,29 +228,16 @@ contract('USDTieredSTO Sim', accounts => { I_USDTieredSTOProxyFactory = await USDTieredSTOProxyFactory.new({ from: POLYMATH }); // STEP 6: Deploy the USDTieredSTOFactory - + I_USDTieredSTOFactory = await USDTieredSTOFactory.new(I_PolyToken.address, STOSetupCost, 0, 0, I_USDTieredSTOProxyFactory.address, { from: ISSUER }); - + assert.notEqual( I_USDTieredSTOFactory.address.valueOf(), "0x0000000000000000000000000000000000000000", "USDTieredSTOFactory contract was not deployed" ); - - - // STEP 7: Register the Modules with the ModuleRegistry contract - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: POLYMATH }); - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); - - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: ISSUER }); - await I_MRProxied.verifyModule(I_USDTieredSTOFactory.address, true, { from: POLYMATH }); // Step 8: Deploy the STFactory contract @@ -285,6 +272,20 @@ contract('USDTieredSTO Sim', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: POLYMATH}); await I_MRProxied.updateFromRegistry({from: POLYMATH}); + // STEP 7: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: POLYMATH }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); + + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: ISSUER }); + await I_MRProxied.verifyModule(I_USDTieredSTOFactory.address, true, { from: POLYMATH }); + // 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 diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index 91b7ab7d5..e4a39b9e3 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -78,7 +78,7 @@ contract('Concurrent STO', accounts => { const MRProxyParameters = ['address', 'address']; const DummySTOParameters = ['uint256', 'uint256', 'uint256', 'string']; const PresaleSTOParameters = ['uint256']; - + before(async() => { // Accounts setup account_polymath = accounts[0]; @@ -106,7 +106,7 @@ contract('Concurrent STO', accounts => { }); // STEP 3: Deploy the ModuleRegistry - + I_ModuleRegistry = await ModuleRegistry.new({from:account_polymath}); // Step 3 (b): Deploy the proxy and attach the implementation contract to it I_ModuleRegistryProxy = await ModuleRegistryProxy.new({from:account_polymath}); @@ -146,25 +146,6 @@ contract('Concurrent STO', accounts => { "CappedSTOFactory contract was not deployed" ); - // STEP 5: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the STO Factories - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_issuer }); - await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); - - await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_issuer }); - await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); - - await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: account_issuer }); - await I_MRProxied.verifyModule(I_PreSaleSTOFactory.address, true, { from: account_polymath }); // Step 8: Deploy the STFactory contract @@ -199,6 +180,26 @@ contract('Concurrent STO', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the STO Factories + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_issuer }); + await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); + + await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_issuer }); + await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); + + await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: account_issuer }); + await I_MRProxied.verifyModule(I_PreSaleSTOFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- diff --git a/test/s_v130_to_v140_upgrade.js b/test/s_v130_to_v140_upgrade.js index 6c1fa9102..4db50ca9f 100644 --- a/test/s_v130_to_v140_upgrade.js +++ b/test/s_v130_to_v140_upgrade.js @@ -164,19 +164,6 @@ contract('Upgrade from v1.3.0 to v1.4.0', accounts => { "CappedSTOFactory contract was not deployed" ); - // STEP 6: Register the Modules with the ModuleRegistry contract - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: POLYMATH }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); - - // (C) : Register the CappedSTOFactory - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: POLYMATH }); - await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: POLYMATH }); - // Step 8: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : POLYMATH }); assert.notEqual( @@ -220,6 +207,19 @@ contract('Upgrade from v1.3.0 to v1.4.0', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_STRProxied.address, {from: POLYMATH}); await I_MRProxied.updateFromRegistry({from: POLYMATH}); + // STEP 6: Register the Modules with the ModuleRegistry contract + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: POLYMATH }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); + + // (C) : Register the CappedSTOFactory + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: POLYMATH }); + await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: POLYMATH }); + // Step 12: Mint tokens to ISSUERs await I_PolyToken.getTokens(REGFEE * 2, ISSUER1); await I_PolyToken.getTokens(REGFEE * 2, ISSUER2); diff --git a/test/t_security_token_registry_proxy.js b/test/t_security_token_registry_proxy.js index cb313cb9d..2dcafde5c 100644 --- a/test/t_security_token_registry_proxy.js +++ b/test/t_security_token_registry_proxy.js @@ -103,10 +103,6 @@ contract ("SecurityTokenRegistryProxy", accounts => { // Register the Modules with the ModuleRegistry contract - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - // Step 3: Deploy the STFactory contract @@ -135,6 +131,10 @@ contract ("SecurityTokenRegistryProxy", accounts => { await I_PolymathRegistry.changeAddress("FeatureRegistry", I_FeatureRegistry.address, {from: account_polymath}); await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` diff --git a/test/u_module_registry_proxy.js b/test/u_module_registry_proxy.js index b6fcc5db5..133d9394c 100644 --- a/test/u_module_registry_proxy.js +++ b/test/u_module_registry_proxy.js @@ -110,6 +110,10 @@ contract ("ModuleRegistryProxy", accounts => { await I_PolymathRegistry.changeAddress("FeatureRegistry", I_FeatureRegistry.address, {from: account_polymath}); await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` @@ -154,11 +158,6 @@ contract ("ModuleRegistryProxy", accounts => { // Register the Modules with the ModuleRegistry contract - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // Step 3: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); From 5a01e07eccfd832148a1b8b02cee53d037c25cf6 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 23:04:07 +0100 Subject: [PATCH 41/63] More test fixes --- test/k_module_registry.js | 22 +++++----------------- test/m_presale_sto.js | 2 +- test/n_security_token_registry.js | 2 +- test/p_usd_tiered_sto.js | 2 +- test/q_usd_tiered_sto_sim.js | 2 +- test/r_concurrent_STO.js | 6 +++--- test/u_module_registry_proxy.js | 9 +++++---- 7 files changed, 17 insertions(+), 28 deletions(-) diff --git a/test/k_module_registry.js b/test/k_module_registry.js index 34007d27d..bc728259f 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -393,7 +393,7 @@ contract('ModuleRegistry', accounts => { assert.ok(errorThrown, message); }); - it("Should fail to add module because custom modules not allowed", async() => { + it("Should fail to register module because custom modules not allowed", async() => { I_CappedSTOFactory2 = await CappedSTOFactory.new(I_PolyToken.address, 0, 0, 0, { from: token_owner }); assert.notEqual( @@ -402,29 +402,17 @@ contract('ModuleRegistry', accounts => { "CappedSTOFactory contract was not deployed" ); - let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); - - assert.equal( - tx.logs[0].args._moduleFactory, - I_CappedSTOFactory2.address, - "CappedSTOFactory is not registerd successfully" - ); - - assert.equal(tx.logs[0].args._owner, token_owner); - - startTime = latestTime() + duration.seconds(5000); - endTime = startTime + duration.days(30); - let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let errorThrown = false; try { - tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); + let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); } catch(error) { errorThrown = true; console.log(` tx revert -> Module is un-verified`.grey); ensureException(error); } assert.ok(errorThrown, message); + }); it("Should switch customModulesAllowed to true", async() => { @@ -437,8 +425,8 @@ contract('ModuleRegistry', accounts => { startTime = latestTime() + duration.seconds(5000); endTime = startTime + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); - - let tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); + let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); + tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); assert.equal(tx.logs[2].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal( diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index ff3d8ffdf..acc04642d 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -194,7 +194,7 @@ contract('PreSaleSTO', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: token_owner }); + await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_PreSaleSTOFactory.address, true, { from: account_polymath }); // Printing all the contract addresses diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index 196186646..1ce5a875d 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -181,7 +181,7 @@ contract('SecurityTokenRegistry', accounts => { ); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: token_owner }); + await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); // Step 9: Deploy the SecurityTokenRegistry diff --git a/test/p_usd_tiered_sto.js b/test/p_usd_tiered_sto.js index 4be82a435..1acc0ef7d 100644 --- a/test/p_usd_tiered_sto.js +++ b/test/p_usd_tiered_sto.js @@ -311,7 +311,7 @@ contract('USDTieredSTO', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: ISSUER }); + await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: POLYMATH }); await I_MRProxied.verifyModule(I_USDTieredSTOFactory.address, true, { from: POLYMATH }); // Step 12: Deploy & Register Mock Oracles diff --git a/test/q_usd_tiered_sto_sim.js b/test/q_usd_tiered_sto_sim.js index 965479485..cd00ccb8d 100644 --- a/test/q_usd_tiered_sto_sim.js +++ b/test/q_usd_tiered_sto_sim.js @@ -283,7 +283,7 @@ contract('USDTieredSTO Sim', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: POLYMATH }); // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: ISSUER }); + await I_MRProxied.registerModule(I_USDTieredSTOFactory.address, { from: POLYMATH }); await I_MRProxied.verifyModule(I_USDTieredSTOFactory.address, true, { from: POLYMATH }); // Step 12: Deploy & Register Mock Oracles diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index e4a39b9e3..c86d53a43 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -191,13 +191,13 @@ contract('Concurrent STO', accounts => { await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); // (C) : Register the STO Factories - await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_issuer }); + await I_MRProxied.registerModule(I_CappedSTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_CappedSTOFactory.address, true, { from: account_polymath }); - await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_issuer }); + await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_DummySTOFactory.address, true, { from: account_polymath }); - await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: account_issuer }); + await I_MRProxied.registerModule(I_PreSaleSTOFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_PreSaleSTOFactory.address, true, { from: account_polymath }); // Printing all the contract addresses diff --git a/test/u_module_registry_proxy.js b/test/u_module_registry_proxy.js index 133d9394c..b6fcc5db5 100644 --- a/test/u_module_registry_proxy.js +++ b/test/u_module_registry_proxy.js @@ -110,10 +110,6 @@ contract ("ModuleRegistryProxy", accounts => { await I_PolymathRegistry.changeAddress("FeatureRegistry", I_FeatureRegistry.address, {from: account_polymath}); await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - // Printing all the contract addresses console.log(` @@ -158,6 +154,11 @@ contract ("ModuleRegistryProxy", accounts => { // Register the Modules with the ModuleRegistry contract + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // Step 3: Deploy the STFactory contract I_STFactory = await STFactory.new(I_GeneralTransferManagerFactory.address, {from : account_polymath }); From 0658566d8302dd11c11a8045f41c34f480b756e6 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 23:14:57 +0100 Subject: [PATCH 42/63] Last fix --- test/n_security_token_registry.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index 1ce5a875d..e51bea0bd 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -180,9 +180,6 @@ contract('SecurityTokenRegistry', accounts => { "TestSTOFactory contract was not deployed" ); - // (C) : Register the STOFactory - await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); - // Step 9: Deploy the SecurityTokenRegistry I_SecurityTokenRegistry = await SecurityTokenRegistry.new({from: account_polymath }); @@ -230,6 +227,9 @@ contract('SecurityTokenRegistry', accounts => { await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + // (C) : Register the STOFactory + await I_MRProxied.registerModule(I_DummySTOFactory.address, { from: account_polymath }); + console.log(` --------------------- Polymath Network Smart Contracts: --------------------- PolymathRegistry: ${PolymathRegistry.address} From 1c7ed17f3b5701e25fb8a19f42e88e5d92e32f1f Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 23:31:07 +0100 Subject: [PATCH 43/63] Fix modifyTicker --- contracts/SecurityTokenRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/SecurityTokenRegistry.sol b/contracts/SecurityTokenRegistry.sol index 606a82722..438e2eef5 100644 --- a/contracts/SecurityTokenRegistry.sol +++ b/contracts/SecurityTokenRegistry.sol @@ -349,7 +349,7 @@ contract SecurityTokenRegistry is ISecurityTokenRegistry, EternalStorage { assert(_tickerOwner(_ticker) == _owner); deleteArrayBytes32(ownerKey, index); if (getArrayBytes32(ownerKey).length > index) { - bytes32 switchedTicker = tickers[index]; + bytes32 switchedTicker = getArrayBytes32(ownerKey)[index]; set(Encoder.getKey("tickerIndex", Util.bytes32ToString(switchedTicker)), index); } } From 37b0b9674733da1405376a80a02fd0afe6fbcfc9 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Mon, 1 Oct 2018 23:36:52 +0100 Subject: [PATCH 44/63] Add more test cases --- test/n_security_token_registry.js | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index 5b09d6160..f4ec3856f 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -1137,6 +1137,58 @@ contract('SecurityTokenRegistry', accounts => { }); }) + describe(" Test cases of the registerTicker", async() => { + + it("Should register the ticker 1", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("1000"), { from: account_temp}); + let tx = await I_STRProxied.registerTicker(account_temp, "TOK1", "", { from: account_temp }); + assert.equal(tx.logs[0].args._owner, account_temp, `Owner should be the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK1", `Symbol should be TOK1`); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should register the ticker 2", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("1000"), { from: account_temp}); + let tx = await I_STRProxied.registerTicker(account_temp, "TOK2", "", { from: account_temp }); + assert.equal(tx.logs[0].args._owner, account_temp, `Owner should be the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK2", `Symbol should be TOK2`); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should register the ticker 3", async () => { + await I_PolyToken.getTokens(web3.utils.toWei("1000"), account_temp); + await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("1000"), { from: account_temp}); + let tx = await I_STRProxied.registerTicker(account_temp, "TOK3", "", { from: account_temp }); + assert.equal(tx.logs[0].args._owner, account_temp, `Owner should be the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK3", `Symbol should be TOK3`); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should successfully remove the ticker 2", async() => { + let tx = await I_STRProxied.removeTicker("TOK2", {from: account_polymath}); + assert.equal(tx.logs[0].args._ticker, "TOK2", "Ticker doesn't get deleted successfully"); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }); + + it("Should modify ticker 1", async() => { + let tx = await I_STRProxied.modifyTicker(account_temp, "TOK1", "TOKEN 1", latestTime(), (latestTime() + duration.minutes(10)), false, {from: account_polymath}); + assert.equal(tx.logs[0].args._owner, account_temp, `Should be equal to the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK1", "Should be equal to TOK1"); + assert.equal(tx.logs[0].args._name, "TOKEN 1", "Should be equal to TOKEN 1"); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }) + + it("Should modify ticker 3", async() => { + let tx = await I_STRProxied.modifyTicker(account_temp, "TOK3", "TOKEN 3", latestTime(), (latestTime() + duration.minutes(10)), false, {from: account_polymath}); + assert.equal(tx.logs[0].args._owner, account_temp, `Should be equal to the ${account_temp}`); + assert.equal(tx.logs[0].args._ticker, "TOK3", "Should be equal to TOK3"); + assert.equal(tx.logs[0].args._name, "TOKEN 3", "Should be equal to TOKEN 3"); + console.log((await I_STRProxied.getTickersByOwner.call(account_temp)).map(x => web3.utils.toAscii(x))); + }) + + }); describe("Test cases for IRegistry functionality", async() => { describe("Test cases for reclaiming funds", async() => { From 213b318984176aedecc31e624c88c13cad913f45 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 10:40:21 +0530 Subject: [PATCH 45/63] Added name to dividend struct --- .../modules/Checkpoint/DividendCheckpoint.sol | 453 +++++++++--------- .../Checkpoint/ERC20DividendCheckpoint.sol | 362 ++++++++------ .../ERC20DividendCheckpointFactory.sol | 200 ++++---- .../Checkpoint/EtherDividendCheckpoint.sol | 329 +++++++------ .../EtherDividendCheckpointFactory.sol | 200 ++++---- contracts/modules/Checkpoint/ICheckpoint.sol | 16 +- test/e_erc20_dividends.js | 26 +- test/f_ether_dividends.js | 24 +- 8 files changed, 849 insertions(+), 761 deletions(-) diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index d751e02fe..3842bf5df 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -1,226 +1,227 @@ -pragma solidity ^0.4.24; - -import "./ICheckpoint.sol"; -import "../Module.sol"; -import "../../interfaces/ISecurityToken.sol"; -import "openzeppelin-solidity/contracts/math/SafeMath.sol"; -import "openzeppelin-solidity/contracts/math/Math.sol"; - -/** - * @title Checkpoint module for issuing ether dividends - * @dev abstract contract - */ -contract DividendCheckpoint is ICheckpoint, Module { - using SafeMath for uint256; - - uint256 public EXCLUDED_ADDRESS_LIMIT = 50; - bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; - - struct Dividend { - uint256 checkpointId; - uint256 created; // Time at which the dividend was created - uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass - uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - set to very high value to bypass - uint256 amount; // Dividend amount in WEI - uint256 claimedAmount; // Amount of dividend claimed so far - uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) - bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend - uint256 dividendWithheld; - uint256 dividendWithheldReclaimed; - mapping (address => bool) claimed; // List of addresses which have claimed dividend - mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends - } - - // List of all dividends - Dividend[] public dividends; - - // List of addresses which cannot claim dividends - address[] public excluded; - - // Mapping from address to withholding tax as a percentage * 10**16 - mapping (address => uint256) public withholdingTax; - - // Total amount of ETH withheld per investor - mapping (address => uint256) public investorWithheld; - - event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); - event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); - event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); - - modifier validDividendIndex(uint256 _dividendIndex) { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - require(now >= dividends[_dividendIndex].maturity, "Dividend maturity is in the future"); - require(now < dividends[_dividendIndex].expiry, "Dividend expiry is in the past"); - require(!dividends[_dividendIndex].reclaimed, "Dividend has been reclaimed by issuer"); - _; - } - - /** - * @notice Init function i.e generalise function to maintain the structure of the module contract - * @return bytes4 - */ - function getInitFunction() public pure returns (bytes4) { - return bytes4(0); - } - - /** - * @notice Return the default excluded addresses - * @return List of excluded addresses - */ - function getDefaultExcluded() external view returns (address[]) { - return excluded; - } - - /** - * @notice Function to clear and set list of excluded addresses used for future dividends - * @param _excluded addresses of investor - */ - function setDefaultExcluded(address[] _excluded) public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); - excluded = _excluded; - emit SetDefaultExcludedAddresses(excluded, now); - } - - /** - * @notice Function to set withholding tax rates for investors - * @param _investors addresses of investor - * @param _withholding withholding tax for individual investors (multiplied by 10**16) - */ - function setWithholding(address[] _investors, uint256[] _withholding) public onlyOwner { - require(_investors.length == _withholding.length, "Mismatched input lengths"); - emit SetWithholding(_investors, _withholding, now); - for (uint256 i = 0; i < _investors.length; i++) { - require(_withholding[i] <= 10**18, "Incorrect withholding tax"); - withholdingTax[_investors[i]] = _withholding[i]; - } - } - - /** - * @notice Function to set withholding tax rates for investors - * @param _investors addresses of investor - * @param _withholding withholding tax for all investors (multiplied by 10**16) - */ - function setWithholdingFixed(address[] _investors, uint256 _withholding) public onlyOwner { - require(_withholding <= 10**18, "Incorrect withholding tax"); - emit SetWithholdingFixed(_investors, _withholding, now); - for (uint256 i = 0; i < _investors.length; i++) { - withholdingTax[_investors[i]] = _withholding; - } - } - - /** - * @notice Issuer can push dividends to provided addresses - * @param _dividendIndex Dividend to push - * @param _payees Addresses to which to push the dividend - */ - function pushDividendPaymentToAddresses(uint256 _dividendIndex, address[] _payees) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { - Dividend storage dividend = dividends[_dividendIndex]; - for (uint256 i = 0; i < _payees.length; i++) { - if ((!dividend.claimed[_payees[i]]) && (!dividend.dividendExcluded[_payees[i]])) { - _payDividend(_payees[i], dividend, _dividendIndex); - } - } - } - - /** - * @notice Issuer can push dividends using the investor list from the security token - * @param _dividendIndex Dividend to push - * @param _start Index in investor list at which to start pushing dividends - * @param _iterations Number of addresses to push dividends for - */ - function pushDividendPayment(uint256 _dividendIndex, uint256 _start, uint256 _iterations) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { - Dividend storage dividend = dividends[_dividendIndex]; - uint256 numberInvestors = ISecurityToken(securityToken).getInvestorsLength(); - for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { - address payee = ISecurityToken(securityToken).investors(i); - if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { - _payDividend(payee, dividend, _dividendIndex); - } - } - } - - /** - * @notice Investors can pull their own dividends - * @param _dividendIndex Dividend to pull - */ - function pullDividendPayment(uint256 _dividendIndex) public validDividendIndex(_dividendIndex) - { - Dividend storage dividend = dividends[_dividendIndex]; - require(!dividend.claimed[msg.sender], "Dividend already claimed by msg.sender"); - require(!dividend.dividendExcluded[msg.sender], "msg.sender excluded from Dividend"); - _payDividend(msg.sender, dividend, _dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee address of investor - * @param _dividend storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal; - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external; - - /** - * @notice Calculate amount of dividends claimable - * @param _dividendIndex Dividend to calculate - * @param _payee Affected investor address - * @return claim, withheld amounts - */ - function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - Dividend storage dividend = dividends[_dividendIndex]; - if (dividend.claimed[_payee] || dividend.dividendExcluded[_payee]) { - return (0, 0); - } - uint256 balance = ISecurityToken(securityToken).balanceOfAt(_payee, dividend.checkpointId); - uint256 claim = balance.mul(dividend.amount).div(dividend.totalSupply); - uint256 withheld = claim.mul(withholdingTax[_payee]).div(uint256(10**18)); - return (claim, withheld); - } - - /** - * @notice Get the index according to the checkpoint id - * @param _checkpointId Checkpoint id to query - * @return uint256[] - */ - function getDividendIndex(uint256 _checkpointId) public view returns(uint256[]) { - uint256 counter = 0; - for(uint256 i = 0; i < dividends.length; i++) { - if (dividends[i].checkpointId == _checkpointId) { - counter++; - } - } - - uint256[] memory index = new uint256[](counter); - counter = 0; - for(uint256 j = 0; j < dividends.length; j++) { - if (dividends[j].checkpointId == _checkpointId) { - index[counter] = j; - counter++; - } - } - return index; - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external; - - /** - * @notice Return the permissions flag that are associated with STO - * @return bytes32 array - */ - function getPermissions() public view returns(bytes32[]) { - bytes32[] memory allPermissions = new bytes32[](1); - allPermissions[0] = DISTRIBUTE; - return allPermissions; - } - -} +pragma solidity ^0.4.24; + +import "./ICheckpoint.sol"; +import "../Module.sol"; +import "../../interfaces/ISecurityToken.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "openzeppelin-solidity/contracts/math/Math.sol"; + +/** + * @title Checkpoint module for issuing ether dividends + * @dev abstract contract + */ +contract DividendCheckpoint is ICheckpoint, Module { + using SafeMath for uint256; + + uint256 public EXCLUDED_ADDRESS_LIMIT = 50; + bytes32 public constant DISTRIBUTE = "DISTRIBUTE"; + + struct Dividend { + uint256 checkpointId; + uint256 created; // Time at which the dividend was created + uint256 maturity; // Time after which dividend can be claimed - set to 0 to bypass + uint256 expiry; // Time until which dividend can be claimed - after this time any remaining amount can be withdrawn by issuer - set to very high value to bypass + uint256 amount; // Dividend amount in WEI + uint256 claimedAmount; // Amount of dividend claimed so far + uint256 totalSupply; // Total supply at the associated checkpoint (avoids recalculating this) + bool reclaimed; // True if expiry has passed and issuer has reclaimed remaining dividend + uint256 dividendWithheld; + uint256 dividendWithheldReclaimed; + mapping (address => bool) claimed; // List of addresses which have claimed dividend + mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends + string name; // Name/title - used for identification + } + + // List of all dividends + Dividend[] public dividends; + + // List of addresses which cannot claim dividends + address[] public excluded; + + // Mapping from address to withholding tax as a percentage * 10**16 + mapping (address => uint256) public withholdingTax; + + // Total amount of ETH withheld per investor + mapping (address => uint256) public investorWithheld; + + event SetDefaultExcludedAddresses(address[] _excluded, uint256 _timestamp); + event SetWithholding(address[] _investors, uint256[] _withholding, uint256 _timestamp); + event SetWithholdingFixed(address[] _investors, uint256 _withholding, uint256 _timestamp); + + modifier validDividendIndex(uint256 _dividendIndex) { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + require(now >= dividends[_dividendIndex].maturity, "Dividend maturity is in the future"); + require(now < dividends[_dividendIndex].expiry, "Dividend expiry is in the past"); + require(!dividends[_dividendIndex].reclaimed, "Dividend has been reclaimed by issuer"); + _; + } + + /** + * @notice Init function i.e generalise function to maintain the structure of the module contract + * @return bytes4 + */ + function getInitFunction() public pure returns (bytes4) { + return bytes4(0); + } + + /** + * @notice Return the default excluded addresses + * @return List of excluded addresses + */ + function getDefaultExcluded() external view returns (address[]) { + return excluded; + } + + /** + * @notice Function to clear and set list of excluded addresses used for future dividends + * @param _excluded addresses of investor + */ + function setDefaultExcluded(address[] _excluded) public onlyOwner { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many excluded addresses"); + excluded = _excluded; + emit SetDefaultExcludedAddresses(excluded, now); + } + + /** + * @notice Function to set withholding tax rates for investors + * @param _investors addresses of investor + * @param _withholding withholding tax for individual investors (multiplied by 10**16) + */ + function setWithholding(address[] _investors, uint256[] _withholding) public onlyOwner { + require(_investors.length == _withholding.length, "Mismatched input lengths"); + emit SetWithholding(_investors, _withholding, now); + for (uint256 i = 0; i < _investors.length; i++) { + require(_withholding[i] <= 10**18, "Incorrect withholding tax"); + withholdingTax[_investors[i]] = _withholding[i]; + } + } + + /** + * @notice Function to set withholding tax rates for investors + * @param _investors addresses of investor + * @param _withholding withholding tax for all investors (multiplied by 10**16) + */ + function setWithholdingFixed(address[] _investors, uint256 _withholding) public onlyOwner { + require(_withholding <= 10**18, "Incorrect withholding tax"); + emit SetWithholdingFixed(_investors, _withholding, now); + for (uint256 i = 0; i < _investors.length; i++) { + withholdingTax[_investors[i]] = _withholding; + } + } + + /** + * @notice Issuer can push dividends to provided addresses + * @param _dividendIndex Dividend to push + * @param _payees Addresses to which to push the dividend + */ + function pushDividendPaymentToAddresses(uint256 _dividendIndex, address[] _payees) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { + Dividend storage dividend = dividends[_dividendIndex]; + for (uint256 i = 0; i < _payees.length; i++) { + if ((!dividend.claimed[_payees[i]]) && (!dividend.dividendExcluded[_payees[i]])) { + _payDividend(_payees[i], dividend, _dividendIndex); + } + } + } + + /** + * @notice Issuer can push dividends using the investor list from the security token + * @param _dividendIndex Dividend to push + * @param _start Index in investor list at which to start pushing dividends + * @param _iterations Number of addresses to push dividends for + */ + function pushDividendPayment(uint256 _dividendIndex, uint256 _start, uint256 _iterations) public withPerm(DISTRIBUTE) validDividendIndex(_dividendIndex) { + Dividend storage dividend = dividends[_dividendIndex]; + uint256 numberInvestors = ISecurityToken(securityToken).getInvestorsLength(); + for (uint256 i = _start; i < Math.min256(numberInvestors, _start.add(_iterations)); i++) { + address payee = ISecurityToken(securityToken).investors(i); + if ((!dividend.claimed[payee]) && (!dividend.dividendExcluded[payee])) { + _payDividend(payee, dividend, _dividendIndex); + } + } + } + + /** + * @notice Investors can pull their own dividends + * @param _dividendIndex Dividend to pull + */ + function pullDividendPayment(uint256 _dividendIndex) public validDividendIndex(_dividendIndex) + { + Dividend storage dividend = dividends[_dividendIndex]; + require(!dividend.claimed[msg.sender], "Dividend already claimed by msg.sender"); + require(!dividend.dividendExcluded[msg.sender], "msg.sender excluded from Dividend"); + _payDividend(msg.sender, dividend, _dividendIndex); + } + + /** + * @notice Internal function for paying dividends + * @param _payee address of investor + * @param _dividend storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal; + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external; + + /** + * @notice Calculate amount of dividends claimable + * @param _dividendIndex Dividend to calculate + * @param _payee Affected investor address + * @return claim, withheld amounts + */ + function calculateDividend(uint256 _dividendIndex, address _payee) public view returns(uint256, uint256) { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + Dividend storage dividend = dividends[_dividendIndex]; + if (dividend.claimed[_payee] || dividend.dividendExcluded[_payee]) { + return (0, 0); + } + uint256 balance = ISecurityToken(securityToken).balanceOfAt(_payee, dividend.checkpointId); + uint256 claim = balance.mul(dividend.amount).div(dividend.totalSupply); + uint256 withheld = claim.mul(withholdingTax[_payee]).div(uint256(10**18)); + return (claim, withheld); + } + + /** + * @notice Get the index according to the checkpoint id + * @param _checkpointId Checkpoint id to query + * @return uint256[] + */ + function getDividendIndex(uint256 _checkpointId) public view returns(uint256[]) { + uint256 counter = 0; + for(uint256 i = 0; i < dividends.length; i++) { + if (dividends[i].checkpointId == _checkpointId) { + counter++; + } + } + + uint256[] memory index = new uint256[](counter); + counter = 0; + for(uint256 j = 0; j < dividends.length; j++) { + if (dividends[j].checkpointId == _checkpointId) { + index[counter] = j; + counter++; + } + } + return index; + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external; + + /** + * @notice Return the permissions flag that are associated with STO + * @return bytes32 array + */ + function getPermissions() public view returns(bytes32[]) { + bytes32[] memory allPermissions = new bytes32[](1); + allPermissions[0] = DISTRIBUTE; + return allPermissions; + } + +} diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol index ad61b24a8..703a81128 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol @@ -1,157 +1,205 @@ -pragma solidity ^0.4.24; - -import "./DividendCheckpoint.sol"; -import "../../interfaces/IERC20.sol"; - -/** - * @title Checkpoint module for issuing ERC20 dividends - */ -contract ERC20DividendCheckpoint is DividendCheckpoint { - using SafeMath for uint256; - - // Mapping to token address for each dividend - mapping (uint256 => address) public dividendTokens; - - event ERC20DividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, address indexed _token, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex); - event ERC20DividendClaimed(address indexed _payee, uint256 _dividendIndex, address indexed _token, uint256 _amount, uint256 _withheld); - event ERC20DividendReclaimed(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _claimedAmount); - event ERC20DividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _withheldAmount); - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public - Module(_securityToken, _polyAddress) - { - } - - /** - * @notice Creates a dividend and checkpoint for the dividend - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - */ - function createDividend(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount) external onlyOwner { - createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - */ - function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId) external onlyOwner { - createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded); - } - - /** - * @notice Creates a dividend and checkpoint for the dividend - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _excluded List of addresses to exclude - */ - function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, address[] _excluded) public onlyOwner { - uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); - createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _token Address of ERC20 token in which dividend is to be denominated - * @param _amount Amount of specified token for dividend - * @param _checkpointId Checkpoint id from which to create dividends - * @param _excluded List of addresses to exclude - */ - function createDividendWithCheckpointAndExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId, address[] _excluded) public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); - require(_expiry > _maturity, "Expiry is before maturity"); - require(_expiry > now, "Expiry is in the past"); - require(_amount > 0, "No dividend sent"); - require(_token != address(0), "0x not valid token"); - require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint"); - require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "Unable to transfer tokens for dividend"); - uint256 dividendIndex = dividends.length; - uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); - uint256 excludedSupply = 0; - for (uint256 i = 0; i < _excluded.length; i++) { - excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); - } - dividends.push( - Dividend( - _checkpointId, - now, - _maturity, - _expiry, - _amount, - 0, - currentSupply.sub(excludedSupply), - false, - 0, - 0 - ) - ); - for (uint256 j = 0; j < _excluded.length; j++) { - dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; - } - dividendTokens[dividendIndex] = _token; - emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee address of investor - * @param _dividend storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { - (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); - _dividend.claimed[_payee] = true; - _dividend.claimedAmount = claim.add(_dividend.claimedAmount); - uint256 claimAfterWithheld = claim.sub(withheld); - if (claimAfterWithheld > 0) { - require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "Unable to transfer tokens"); - _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); - investorWithheld[_payee] = investorWithheld[_payee].add(withheld); - emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld); - } - } - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); - require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); - dividends[_dividendIndex].reclaimed = true; - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); - require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingAmount), "Unable to transfer tokens"); - emit ERC20DividendReclaimed(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingAmount); - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); - dividend.dividendWithheldReclaimed = dividend.dividendWithheld; - require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingWithheld), "Unable to transfer tokens"); - emit ERC20DividendWithholdingWithdrawn(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld); - } - -} +pragma solidity ^0.4.24; + +import "./DividendCheckpoint.sol"; +import "../../interfaces/IERC20.sol"; + +/** + * @title Checkpoint module for issuing ERC20 dividends + */ +contract ERC20DividendCheckpoint is DividendCheckpoint { + using SafeMath for uint256; + + // Mapping to token address for each dividend + mapping (uint256 => address) public dividendTokens; + + event ERC20DividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, address indexed _token, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, string _name); + event ERC20DividendClaimed(address indexed _payee, uint256 _dividendIndex, address indexed _token, uint256 _amount, uint256 _withheld); + event ERC20DividendReclaimed(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _claimedAmount); + event ERC20DividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _withheldAmount); + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice Creates a dividend and checkpoint for the dividend + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _name name/title for identification + */ + function createDividend(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, string _name) external onlyOwner { + createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _name name/title for identification + */ + function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId, string _name) external onlyOwner { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded, _name); + } + + /** + * @notice Creates a dividend and checkpoint for the dividend + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, address[] _excluded, string _name) public onlyOwner { + uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + address[] _excluded, + string _name + ) + public + onlyOwner + { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _token Address of ERC20 token in which dividend is to be denominated + * @param _amount Amount of specified token for dividend + * @param _checkpointId Checkpoint id from which to create dividends + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function _createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + address _token, + uint256 _amount, + uint256 _checkpointId, + address[] _excluded, + string _name + ) + internal + { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); + require(_expiry > _maturity, "Expiry is before maturity"); + require(_expiry > now, "Expiry is in the past"); + require(_amount > 0, "No dividend sent"); + require(_token != address(0), "0x not valid token"); + require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint"); + require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "Unable to transfer tokens for dividend"); + uint256 dividendIndex = dividends.length; + uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); + uint256 excludedSupply = 0; + for (uint256 i = 0; i < _excluded.length; i++) { + excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); + } + dividends.push( + Dividend( + _checkpointId, + now, + _maturity, + _expiry, + _amount, + 0, + currentSupply.sub(excludedSupply), + false, + 0, + 0, + _name + ) + ); + for (uint256 j = 0; j < _excluded.length; j++) { + dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; + } + dividendTokens[dividendIndex] = _token; + _CallERC20DividendDepositedEvent(_checkpointId, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + } + + /** + * @notice emits the ERC20DividendDeposited event. + * Seperated into a different function to work around the Stack too deep error + */ + function _CallERC20DividendDepositedEvent(uint256 _checkpointId, uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 currentSupply, uint256 dividendIndex, string _name) internal { + emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + } + + /** + * @notice Internal function for paying dividends + * @param _payee address of investor + * @param _dividend storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { + (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); + _dividend.claimed[_payee] = true; + _dividend.claimedAmount = claim.add(_dividend.claimedAmount); + uint256 claimAfterWithheld = claim.sub(withheld); + if (claimAfterWithheld > 0) { + require(IERC20(dividendTokens[_dividendIndex]).transfer(_payee, claimAfterWithheld), "Unable to transfer tokens"); + _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); + investorWithheld[_payee] = investorWithheld[_payee].add(withheld); + emit ERC20DividendClaimed(_payee, _dividendIndex, dividendTokens[_dividendIndex], claim, withheld); + } + } + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); + require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); + dividends[_dividendIndex].reclaimed = true; + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); + require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingAmount), "Unable to transfer tokens"); + emit ERC20DividendReclaimed(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingAmount); + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); + dividend.dividendWithheldReclaimed = dividend.dividendWithheld; + require(IERC20(dividendTokens[_dividendIndex]).transfer(msg.sender, remainingWithheld), "Unable to transfer tokens"); + emit ERC20DividendWithholdingWithdrawn(msg.sender, _dividendIndex, dividendTokens[_dividendIndex], remainingWithheld); + } + +} diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol index d789ad5e3..f71f601c6 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpointFactory.sol @@ -1,100 +1,100 @@ -pragma solidity ^0.4.24; - -import "./ERC20DividendCheckpoint.sol"; -import "../ModuleFactory.sol"; - -/** - * @title Factory for deploying ERC20DividendCheckpoint module - */ -contract ERC20DividendCheckpointFactory is ModuleFactory { - - /** - * @notice Constructor - * @param _polyAddress Address of the polytoken - * @param _setupCost Setup cost of the module - * @param _usageCost Usage cost of the module - * @param _subscriptionCost Subscription cost of the module - */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public - ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { - version = "1.0.0"; - name = "ERC20DividendCheckpoint"; - title = "ERC20 Dividend Checkpoint"; - description = "Create ERC20 dividends for token holders at a specific checkpoint"; - 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 - * @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"); - address erc20DividendCheckpoint = new ERC20DividendCheckpoint(msg.sender, address(polyToken)); - emit GenerateModuleFromFactory(erc20DividendCheckpoint, getName(), address(this), msg.sender, setupCost, now); - return erc20DividendCheckpoint; - } - - /** - * @notice Type of the Module factory - */ - function getType() public view returns(uint8) { - return 4; - } - - /** - * @notice Get the name of the Module - */ - function getName() public view returns(bytes32) { - return name; - } - - /** - * @notice Get the description of the Module - */ - function getDescription() public view returns(string) { - return description; - } - - /** - * @notice Get the title of the Module - */ - function getTitle() public 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 Get the Instructions that helped to used the module - */ - function getInstructions() public view returns(string) { - return "Create a ERC20 dividend which will be paid out to token holders proportional to their balances at the point the dividend is created"; - } - - /** - * @notice Get the tags related to the module factory - */ - function getTags() public view returns(bytes32[]) { - bytes32[] memory availableTags = new bytes32[](3); - availableTags[0] = "ERC20"; - availableTags[1] = "Dividend"; - availableTags[2] = "Checkpoint"; - return availableTags; - } -} +pragma solidity ^0.4.24; + +import "./ERC20DividendCheckpoint.sol"; +import "../ModuleFactory.sol"; + +/** + * @title Factory for deploying ERC20DividendCheckpoint module + */ +contract ERC20DividendCheckpointFactory is ModuleFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + * @param _setupCost Setup cost of the module + * @param _usageCost Usage cost of the module + * @param _subscriptionCost Subscription cost of the module + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + { + version = "1.0.0"; + name = "ERC20DividendCheckpoint"; + title = "ERC20 Dividend Checkpoint"; + description = "Create ERC20 dividends for token holders at a specific checkpoint"; + 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 + * @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"); + address erc20DividendCheckpoint = new ERC20DividendCheckpoint(msg.sender, address(polyToken)); + emit GenerateModuleFromFactory(erc20DividendCheckpoint, getName(), address(this), msg.sender, setupCost, now); + return erc20DividendCheckpoint; + } + + /** + * @notice Type of the Module factory + */ + function getType() public view returns(uint8) { + return 4; + } + + /** + * @notice Get the name of the Module + */ + function getName() public view returns(bytes32) { + return name; + } + + /** + * @notice Get the description of the Module + */ + function getDescription() public view returns(string) { + return description; + } + + /** + * @notice Get the title of the Module + */ + function getTitle() public 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 Get the Instructions that helped to used the module + */ + function getInstructions() public view returns(string) { + return "Create a ERC20 dividend which will be paid out to token holders proportional to their balances at the point the dividend is created"; + } + + /** + * @notice Get the tags related to the module factory + */ + function getTags() public view returns(bytes32[]) { + bytes32[] memory availableTags = new bytes32[](3); + availableTags[0] = "ERC20"; + availableTags[1] = "Dividend"; + availableTags[2] = "Checkpoint"; + return availableTags; + } +} diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol index 1d17e1abb..0a20ee7a3 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol @@ -1,147 +1,182 @@ -pragma solidity ^0.4.24; - -import "./DividendCheckpoint.sol"; - -/** - * @title Checkpoint module for issuing ether dividends - */ -contract EtherDividendCheckpoint is DividendCheckpoint { - using SafeMath for uint256; - - event EtherDividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex); - event EtherDividendClaimed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); - event EtherDividendReclaimed(address indexed _claimer, uint256 _dividendIndex, uint256 _claimedAmount); - event EtherDividendClaimFailed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); - event EtherDividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, uint256 _withheldAmount); - - /** - * @notice Constructor - * @param _securityToken Address of the security token - * @param _polyAddress Address of the polytoken - */ - constructor (address _securityToken, address _polyAddress) public - Module(_securityToken, _polyAddress) - { - } - - /** - * @notice Creates a dividend and checkpoint for the dividend, using global list of excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - */ - function createDividend(uint256 _maturity, uint256 _expiry) payable external onlyOwner { - createDividendWithExclusions(_maturity, _expiry, excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint, using global list of excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _checkpointId Id of the checkpoint from which to issue dividend - */ - function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, uint256 _checkpointId) payable external onlyOwner { - createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, excluded); - } - - /** - * @notice Creates a dividend and checkpoint for the dividend, specifying explicit excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _excluded List of addresses to exclude - */ - function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address[] _excluded) payable public onlyOwner { - uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); - createDividendWithCheckpointAndExclusions(_maturity, _expiry, checkpointId, _excluded); - } - - /** - * @notice Creates a dividend with a provided checkpoint, specifying explicit excluded addresses - * @param _maturity Time from which dividend can be paid - * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer - * @param _checkpointId Id of the checkpoint from which to issue dividend - * @param _excluded List of addresses to exclude - */ - function createDividendWithCheckpointAndExclusions(uint256 _maturity, uint256 _expiry, uint256 _checkpointId, address[] _excluded) payable public onlyOwner { - require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); - require(_expiry > _maturity, "Expiry is before maturity"); - require(_expiry > now, "Expiry is in the past"); - require(msg.value > 0, "No dividend sent"); - require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId()); - uint256 dividendIndex = dividends.length; - uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); - uint256 excludedSupply = 0; - for (uint256 i = 0; i < _excluded.length; i++) { - excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); - } - dividends.push( - Dividend( - _checkpointId, - now, - _maturity, - _expiry, - msg.value, - 0, - currentSupply.sub(excludedSupply), - false, - 0, - 0 - ) - ); - for (uint256 j = 0; j < _excluded.length; j++) { - dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; - } - emit EtherDividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, msg.value, currentSupply, dividendIndex); - } - - /** - * @notice Internal function for paying dividends - * @param _payee address of investor - * @param _dividend storage with previously issued dividends - * @param _dividendIndex Dividend to pay - */ - function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { - (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); - _dividend.claimed[_payee] = true; - uint256 claimAfterWithheld = claim.sub(withheld); - if (claimAfterWithheld > 0) { - if (_payee.send(claimAfterWithheld)) { - _dividend.claimedAmount = _dividend.claimedAmount.add(claim); - _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); - investorWithheld[_payee] = investorWithheld[_payee].add(withheld); - emit EtherDividendClaimed(_payee, _dividendIndex, claim, withheld); - } else { - _dividend.claimed[_payee] = false; - emit EtherDividendClaimFailed(_payee, _dividendIndex, claim, withheld); - } - } - } - - /** - * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends - * @param _dividendIndex Dividend to reclaim - */ - function reclaimDividend(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); - require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); - Dividend storage dividend = dividends[_dividendIndex]; - dividend.reclaimed = true; - uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); - msg.sender.transfer(remainingAmount); - emit EtherDividendReclaimed(msg.sender, _dividendIndex, remainingAmount); - } - - /** - * @notice Allows issuer to withdraw withheld tax - * @param _dividendIndex Dividend to withdraw from - */ - function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { - require(_dividendIndex < dividends.length, "Incorrect dividend index"); - Dividend storage dividend = dividends[_dividendIndex]; - uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); - dividend.dividendWithheldReclaimed = dividend.dividendWithheld; - msg.sender.transfer(remainingWithheld); - emit EtherDividendWithholdingWithdrawn(msg.sender, _dividendIndex, remainingWithheld); - } - -} +pragma solidity ^0.4.24; + +import "./DividendCheckpoint.sol"; + +/** + * @title Checkpoint module for issuing ether dividends + */ +contract EtherDividendCheckpoint is DividendCheckpoint { + using SafeMath for uint256; + + event EtherDividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, string _name); + event EtherDividendClaimed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); + event EtherDividendReclaimed(address indexed _claimer, uint256 _dividendIndex, uint256 _claimedAmount); + event EtherDividendClaimFailed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); + event EtherDividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, uint256 _withheldAmount); + + /** + * @notice Constructor + * @param _securityToken Address of the security token + * @param _polyAddress Address of the polytoken + */ + constructor (address _securityToken, address _polyAddress) public + Module(_securityToken, _polyAddress) + { + } + + /** + * @notice Creates a dividend and checkpoint for the dividend, using global list of excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _name name/title for identification + */ + function createDividend(uint256 _maturity, uint256 _expiry, string _name) payable external onlyOwner { + createDividendWithExclusions(_maturity, _expiry, excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint, using global list of excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _checkpointId Id of the checkpoint from which to issue dividend + * @param _name name/title for identification + */ + function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, uint256 _checkpointId, string _name) payable external onlyOwner { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, excluded, _name); + } + + /** + * @notice Creates a dividend and checkpoint for the dividend, specifying explicit excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address[] _excluded, string _name) payable public onlyOwner { + uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint, specifying explicit excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _checkpointId Id of the checkpoint from which to issue dividend + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + uint256 _checkpointId, + address[] _excluded, + string _name + ) + payable + public + onlyOwner + { + _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, _excluded, _name); + } + + /** + * @notice Creates a dividend with a provided checkpoint, specifying explicit excluded addresses + * @param _maturity Time from which dividend can be paid + * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer + * @param _checkpointId Id of the checkpoint from which to issue dividend + * @param _excluded List of addresses to exclude + * @param _name name/title for identification + */ + function _createDividendWithCheckpointAndExclusions( + uint256 _maturity, + uint256 _expiry, + uint256 _checkpointId, + address[] _excluded, + string _name + ) + internal + { + require(_excluded.length <= EXCLUDED_ADDRESS_LIMIT, "Too many addresses excluded"); + require(_expiry > _maturity, "Expiry is before maturity"); + require(_expiry > now, "Expiry is in the past"); + require(msg.value > 0, "No dividend sent"); + require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId()); + uint256 dividendIndex = dividends.length; + uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); + uint256 excludedSupply = 0; + for (uint256 i = 0; i < _excluded.length; i++) { + excludedSupply = excludedSupply.add(ISecurityToken(securityToken).balanceOfAt(_excluded[i], _checkpointId)); + } + dividends.push( + Dividend( + _checkpointId, + now, + _maturity, + _expiry, + msg.value, + 0, + currentSupply.sub(excludedSupply), + false, + 0, + 0, + _name + ) + ); + for (uint256 j = 0; j < _excluded.length; j++) { + dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; + } + emit EtherDividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, msg.value, currentSupply, dividendIndex, _name); + } + + /** + * @notice Internal function for paying dividends + * @param _payee address of investor + * @param _dividend storage with previously issued dividends + * @param _dividendIndex Dividend to pay + */ + function _payDividend(address _payee, Dividend storage _dividend, uint256 _dividendIndex) internal { + (uint256 claim, uint256 withheld) = calculateDividend(_dividendIndex, _payee); + _dividend.claimed[_payee] = true; + uint256 claimAfterWithheld = claim.sub(withheld); + if (claimAfterWithheld > 0) { + if (_payee.send(claimAfterWithheld)) { + _dividend.claimedAmount = _dividend.claimedAmount.add(claim); + _dividend.dividendWithheld = _dividend.dividendWithheld.add(withheld); + investorWithheld[_payee] = investorWithheld[_payee].add(withheld); + emit EtherDividendClaimed(_payee, _dividendIndex, claim, withheld); + } else { + _dividend.claimed[_payee] = false; + emit EtherDividendClaimFailed(_payee, _dividendIndex, claim, withheld); + } + } + } + + /** + * @notice Issuer can reclaim remaining unclaimed dividend amounts, for expired dividends + * @param _dividendIndex Dividend to reclaim + */ + function reclaimDividend(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + require(now >= dividends[_dividendIndex].expiry, "Dividend expiry is in the future"); + require(!dividends[_dividendIndex].reclaimed, "Dividend already claimed"); + Dividend storage dividend = dividends[_dividendIndex]; + dividend.reclaimed = true; + uint256 remainingAmount = dividend.amount.sub(dividend.claimedAmount); + msg.sender.transfer(remainingAmount); + emit EtherDividendReclaimed(msg.sender, _dividendIndex, remainingAmount); + } + + /** + * @notice Allows issuer to withdraw withheld tax + * @param _dividendIndex Dividend to withdraw from + */ + function withdrawWithholding(uint256 _dividendIndex) external onlyOwner { + require(_dividendIndex < dividends.length, "Incorrect dividend index"); + Dividend storage dividend = dividends[_dividendIndex]; + uint256 remainingWithheld = dividend.dividendWithheld.sub(dividend.dividendWithheldReclaimed); + dividend.dividendWithheldReclaimed = dividend.dividendWithheld; + msg.sender.transfer(remainingWithheld); + emit EtherDividendWithholdingWithdrawn(msg.sender, _dividendIndex, remainingWithheld); + } + +} diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol index 146691d82..d1e8ac50b 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpointFactory.sol @@ -1,100 +1,100 @@ -pragma solidity ^0.4.24; - -import "./EtherDividendCheckpoint.sol"; -import "../ModuleFactory.sol"; - -/** - * @title Factory for deploying EtherDividendCheckpoint module - */ -contract EtherDividendCheckpointFactory is ModuleFactory { - - /** - * @notice Constructor - * @param _polyAddress Address of the polytoken - * @param _setupCost Setup cost of the module - * @param _usageCost Usage cost of the module - * @param _subscriptionCost Subscription cost of the module - */ - constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public - ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) - { - version = "1.0.0"; - name = "EtherDividendCheckpoint"; - title = "Ether Dividend Checkpoint"; - description = "Create ETH dividends for token holders at a specific checkpoint"; - 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 - * @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"); - address ethDividendCheckpoint = new EtherDividendCheckpoint(msg.sender, address(polyToken)); - emit GenerateModuleFromFactory(ethDividendCheckpoint, getName(), address(this), msg.sender, setupCost, now); - return ethDividendCheckpoint; - } - - /** - * @notice Type of the Module factory - */ - function getType() public view returns(uint8) { - return 4; - } - - /** - * @notice Get the name of the Module - */ - function getName() public view returns(bytes32) { - return name; - } - - /** - * @notice Get the description of the Module - */ - function getDescription() public view returns(string) { - return description; - } - - /** - * @notice Get the title of the Module - */ - function getTitle() public 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 Get the Instructions that helped to used the module - */ - function getInstructions() public view returns(string) { - return "Create a dividend which will be paid out to token holders proportional to their balances at the point the dividend is created"; - } - - /** - * @notice Get the tags related to the module factory - */ - function getTags() public view returns(bytes32[]) { - bytes32[] memory availableTags = new bytes32[](3); - availableTags[0] = "ETH"; - availableTags[1] = "Checkpoint"; - availableTags[2] = "Dividend"; - return availableTags; - } -} +pragma solidity ^0.4.24; + +import "./EtherDividendCheckpoint.sol"; +import "../ModuleFactory.sol"; + +/** + * @title Factory for deploying EtherDividendCheckpoint module + */ +contract EtherDividendCheckpointFactory is ModuleFactory { + + /** + * @notice Constructor + * @param _polyAddress Address of the polytoken + * @param _setupCost Setup cost of the module + * @param _usageCost Usage cost of the module + * @param _subscriptionCost Subscription cost of the module + */ + constructor (address _polyAddress, uint256 _setupCost, uint256 _usageCost, uint256 _subscriptionCost) public + ModuleFactory(_polyAddress, _setupCost, _usageCost, _subscriptionCost) + { + version = "1.0.0"; + name = "EtherDividendCheckpoint"; + title = "Ether Dividend Checkpoint"; + description = "Create ETH dividends for token holders at a specific checkpoint"; + 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 + * @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"); + address ethDividendCheckpoint = new EtherDividendCheckpoint(msg.sender, address(polyToken)); + emit GenerateModuleFromFactory(ethDividendCheckpoint, getName(), address(this), msg.sender, setupCost, now); + return ethDividendCheckpoint; + } + + /** + * @notice Type of the Module factory + */ + function getType() public view returns(uint8) { + return 4; + } + + /** + * @notice Get the name of the Module + */ + function getName() public view returns(bytes32) { + return name; + } + + /** + * @notice Get the description of the Module + */ + function getDescription() public view returns(string) { + return description; + } + + /** + * @notice Get the title of the Module + */ + function getTitle() public 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 Get the Instructions that helped to used the module + */ + function getInstructions() public view returns(string) { + return "Create a dividend which will be paid out to token holders proportional to their balances at the point the dividend is created"; + } + + /** + * @notice Get the tags related to the module factory + */ + function getTags() public view returns(bytes32[]) { + bytes32[] memory availableTags = new bytes32[](3); + availableTags[0] = "ETH"; + availableTags[1] = "Checkpoint"; + availableTags[2] = "Dividend"; + return availableTags; + } +} diff --git a/contracts/modules/Checkpoint/ICheckpoint.sol b/contracts/modules/Checkpoint/ICheckpoint.sol index 214093131..3e567ba7b 100644 --- a/contracts/modules/Checkpoint/ICheckpoint.sol +++ b/contracts/modules/Checkpoint/ICheckpoint.sol @@ -1,8 +1,8 @@ -pragma solidity ^0.4.24; - -/** - * @title Interface to be implemented by all checkpoint modules - */ -interface ICheckpoint { - -} +pragma solidity ^0.4.24; + +/** + * @title Interface to be implemented by all checkpoint modules + */ +interface ICheckpoint { + +} diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 395afbec2..af265518c 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -41,6 +41,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiryTime = toTime + duration.days(15); let message = "Transaction Should Fail!"; + let dividendName = "TestDividend"; // Contract Instance Declaration let I_GeneralPermissionManagerFactory; @@ -364,7 +365,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because allowance = 0`.grey); ensureException(error); @@ -379,7 +380,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() - duration.days(10); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -393,7 +394,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(2); let expiry = latestTime() - duration.days(1); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -407,7 +408,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, 0, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, 0, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because token address is 0x`.grey); ensureException(error); @@ -421,7 +422,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); try { - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, 0, {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, 0, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because amount < 0`.grey); ensureException(error); @@ -434,8 +435,9 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 1, "Dividend should be created at checkpoint 1"); + assert.equal(tx.logs[0].args._name.toString(), dividendName, "Dividend name incorrect in event"); }); it("Investor 1 transfers his token balance to investor 2", async() => { @@ -524,7 +526,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 2, "Dividend should be created at checkpoint 1"); }); @@ -589,7 +591,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('11', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('11', 'ether'), {from: token_owner}); - let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 3, "Dividend should be created at checkpoint 2"); }); @@ -676,7 +678,7 @@ contract('ERC20DividendCheckpoint', accounts => { console.log((await I_SecurityToken.currentCheckpointId()).toNumber()); await I_PolyToken.getTokens(web3.utils.toWei('20', 'ether'), token_owner); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because allowance is not provided`.grey); ensureException(error); @@ -709,7 +711,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(5); let expiry = latestTime() - duration.days(2); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -723,7 +725,7 @@ contract('ERC20DividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(2); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 5, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 5, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because checkpoint id > current checkpoint`.grey); ensureException(error); @@ -741,7 +743,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('11', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('11', 'ether'), {from: token_owner}); - let tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), 4, [account_investor1], {from: token_owner}); + let tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, I_PolyToken.address, web3.utils.toWei('10', 'ether'), 4, [account_investor1], dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 4, "Dividend should be created at checkpoint 3"); }); diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 00a8852a2..5cab95fce 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -41,6 +41,7 @@ contract('EtherDividendCheckpoint', accounts => { let expiryTime = toTime + duration.days(15); let message = "Transaction Should Fail!"; + let dividendName = "TestDividend"; // Contract Instance Declaration let I_GeneralPermissionManagerFactory; @@ -364,7 +365,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); try { - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because msg.value = 0`.grey); ensureException(error); @@ -378,7 +379,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() - duration.days(10); try { - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -408,8 +409,9 @@ contract('EtherDividendCheckpoint', accounts => { it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 1, "Dividend should be created at checkpoint 1"); + assert.equal(tx.logs[0].args._name.toString(), dividendName, "Dividend name incorrect in event"); }); it("Investor 1 transfers his token balance to investor 2", async() => { @@ -510,7 +512,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 2, "Dividend should be created at checkpoint 2"); }); @@ -576,7 +578,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Create another new dividend", async() => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 3, "Dividend should be created at checkpoint 3"); }); @@ -662,7 +664,7 @@ contract('EtherDividendCheckpoint', accounts => { let expiry = latestTime() + duration.days(2); let tx = await I_SecurityToken.createCheckpoint({from: token_owner}); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, {from: token_owner, value: 0}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, dividendName, {from: token_owner, value: 0}); } catch(error) { console.log(` tx -> failed because msg.value is 0`.grey); ensureException(error); @@ -676,7 +678,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() - duration.days(10); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); @@ -690,7 +692,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(5); let expiry = latestTime() - duration.days(2); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 4, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); @@ -704,7 +706,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(2); try { - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 5, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, 5, dividendName, {from: token_owner, value: web3.utils.toWei('11', 'ether')}); } catch(error) { console.log(` tx -> failed because checkpoint id > current checkpoint`.grey); ensureException(error); @@ -717,7 +719,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); let tx = await I_SecurityToken.createCheckpoint({from: token_owner}); - tx = await I_EtherDividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, 4, [account_investor1], {from: token_owner, value: web3.utils.toWei('10', 'ether')}); + tx = await I_EtherDividendCheckpoint.createDividendWithCheckpointAndExclusions(maturity, expiry, 4, [account_investor1], dividendName, {from: token_owner, value: web3.utils.toWei('10', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 4, "Dividend should be created at checkpoint 4"); }); @@ -890,7 +892,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Create another new dividend", async() => { let maturity = latestTime(); let expiry = latestTime() + duration.days(10); - let tx = await I_EtherDividendCheckpoint.createDividendWithExclusions(maturity, expiry, [], {from: token_owner, value: web3.utils.toWei('12', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividendWithExclusions(maturity, expiry, [], dividendName, {from: token_owner, value: web3.utils.toWei('12', 'ether')}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 6, "Dividend should be created at checkpoint 6"); }); From 9b626d5531c74ea8933fdd840f61c702f1cb71d8 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 10:57:33 +0530 Subject: [PATCH 46/63] test case typos fixed --- test/e_erc20_dividends.js | 2 +- test/f_ether_dividends.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index af265518c..3530a7fd0 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -695,7 +695,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiry = latestTime() - duration.days(10); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('20', 'ether'), {from: token_owner}); try { - tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, {from: token_owner}); + tx = await I_ERC20DividendCheckpoint.createDividendWithCheckpoint(maturity, expiry, I_PolyToken.address, web3.utils.toWei('20', 'ether'), 4, dividendName, {from: token_owner}); } catch(error) { console.log(` tx -> failed because maturity > expiry`.grey); ensureException(error); diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 5cab95fce..cb3fad8f6 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -393,7 +393,7 @@ contract('EtherDividendCheckpoint', accounts => { let maturity = latestTime() - duration.days(2); let expiry = latestTime() - duration.days(1); try { - let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + let tx = await I_EtherDividendCheckpoint.createDividend(maturity, expiry, dividendName, {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); } catch(error) { console.log(` tx -> failed because now > expiry`.grey); ensureException(error); From 259a4de2af919cd703bcfb67bf0c2aadc6cead82 Mon Sep 17 00:00:00 2001 From: satyam Date: Tue, 2 Oct 2018 12:11:19 +0530 Subject: [PATCH 47/63] small changelog fix --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da8b2497..52e0d50da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,6 @@ All notable changes to this project will be documented in this file. ## Added * Added `getTagsByType`, `getTagsByTypeAndToken`, `getModulesByType`, `getModulesByTypeAndToken` to MR -* Removed `addTagByModuleType` & `removeTagsByModuleType` from MR * Added `getTokensByOwner` to STR * Added withholding tax to ether & erc20 dividends * Generalised MakerDAO oracle to allow different instances referencing different currencies @@ -29,7 +28,8 @@ All notable changes to this project will be documented in this file. ## Removed * Remove `swarmHash` from the `registerTicker(), addCustomTicker(), generateSecurityToken(), addCustomSecurityToken()` functions of TickerRegistry.sol and SecurityTokenRegistry.sol. #230 -* Remove `Log` prefix from all the event present in the ecosystem. +* Remove `Log` prefix from all the event present in the ecosystem. +* Removed `addTagByModuleType` & `removeTagsByModuleType` from MR. ====== From c8195a5645bb871e73cb98af07b477ea90c0bec6 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 09:58:52 +0100 Subject: [PATCH 48/63] Update title --- contracts/libraries/KindMath.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/libraries/KindMath.sol b/contracts/libraries/KindMath.sol index 92d77362e..a9cce4546 100644 --- a/contracts/libraries/KindMath.sol +++ b/contracts/libraries/KindMath.sol @@ -3,7 +3,7 @@ pragma solidity ^0.4.24; // Copied from OpenZeppelin and modified to be friendlier /** - * @title SafeMath + * @title KindMath * @dev Math operations with safety checks that throw on error */ library KindMath { From 840fb8f6ae5158e283f260e64a07c9d62b59e562 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 10:23:48 +0100 Subject: [PATCH 49/63] Fix test case based on registerModule change --- test/v_tracked_redemptions.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index 0f767214f..fe03a8614 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -148,19 +148,6 @@ contract('TrackedRedemption', accounts => { "TrackedRedemptionFactory contract was not deployed" ); - // STEP 5: Register the Modules with the ModuleRegistry contract - - // (A) : Register the GeneralTransferManagerFactory - await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); - - // (B) : Register the GeneralDelegateManagerFactory - await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); - - // (C) : Register the TrackedRedemptionFactory - await I_MRProxied.registerModule(I_TrackedRedemptionFactory.address, { from: account_polymath }); - await I_MRProxied.verifyModule(I_TrackedRedemptionFactory.address, true, { from: account_polymath }); // Step 6: Deploy the STFactory contract @@ -195,6 +182,20 @@ contract('TrackedRedemption', accounts => { await I_PolymathRegistry.changeAddress("SecurityTokenRegistry", I_SecurityTokenRegistryProxy.address, {from: account_polymath}); await I_MRProxied.updateFromRegistry({from: account_polymath}); + // STEP 5: Register the Modules with the ModuleRegistry contract + + // (A) : Register the GeneralTransferManagerFactory + await I_MRProxied.registerModule(I_GeneralTransferManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralTransferManagerFactory.address, true, { from: account_polymath }); + + // (B) : Register the GeneralDelegateManagerFactory + await I_MRProxied.registerModule(I_GeneralPermissionManagerFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_GeneralPermissionManagerFactory.address, true, { from: account_polymath }); + + // (C) : Register the TrackedRedemptionFactory + await I_MRProxied.registerModule(I_TrackedRedemptionFactory.address, { from: account_polymath }); + await I_MRProxied.verifyModule(I_TrackedRedemptionFactory.address, true, { from: account_polymath }); + // Printing all the contract addresses console.log(` --------------------- Polymath Network Smart Contracts: --------------------- From b666431903f3a1cb540da5ed723c1ad6bd274ce1 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 11:39:18 +0100 Subject: [PATCH 50/63] Small fix --- contracts/tokens/SecurityToken.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index 6c866a7df..429114e10 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -667,6 +667,8 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return true; } } + + return false; } /** From 61056d85edea43c21d04e97be234250fb1a023ed Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 16:25:23 +0530 Subject: [PATCH 51/63] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e0d50da..ca2181f6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. [__1.5.0__](https://www.npmjs.com/package/polymath-core?activeTab=readme) __15-08-18__ ## Added +* Added `name` field to dividends struct in DividendCheckpoint. #295 * Added `getTagsByType`, `getTagsByTypeAndToken`, `getModulesByType`, `getModulesByTypeAndToken` to MR * Added `getTokensByOwner` to STR * Added withholding tax to ether & erc20 dividends From 8b79b9138e8a7b1fdd5f475fee9365276d193925 Mon Sep 17 00:00:00 2001 From: Pablo Ruiz Date: Tue, 2 Oct 2018 09:15:04 -0300 Subject: [PATCH 52/63] changed ganache test limit to 8mm --- scripts/test.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index d6fb7a632..f6bb5ee03 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Global variable +# Global variable bridge_pid # Exit script as soon as a command fails. @@ -61,11 +61,11 @@ start_testrpc() { ) if ! [ -z "${TRAVIS_PULL_REQUEST+x}" ] && [ "$TRAVIS_PULL_REQUEST" != false ]; then - node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port "$testrpc_port" "${accounts[@]}" > /dev/null & + node_modules/.bin/testrpc-sc --gasLimit 8000000 --port "$testrpc_port" "${accounts[@]}" > /dev/null & else - node_modules/.bin/ganache-cli --gasLimit 0xfffffffffff "${accounts[@]}" > /dev/null & + node_modules/.bin/ganache-cli --gasLimit 8000000 "${accounts[@]}" > /dev/null & fi - + testrpc_pid=$! } From 6f0f44e171aeabfbe78e20755c72e2336304e102 Mon Sep 17 00:00:00 2001 From: Adam Dossa Date: Tue, 2 Oct 2018 13:16:31 +0100 Subject: [PATCH 53/63] Fix bad merge --- contracts/tokens/SecurityToken.sol | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/contracts/tokens/SecurityToken.sol b/contracts/tokens/SecurityToken.sol index cdfde0d42..8d73a9e00 100644 --- a/contracts/tokens/SecurityToken.sol +++ b/contracts/tokens/SecurityToken.sol @@ -670,7 +670,7 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return false; } - + function _burn(address _from, uint256 _value) internal returns (bool) { require(_value <= balances[_from], "Value too high"); require(_updateTransfer(_from, address(0), _value), "Burn is not valid"); @@ -715,27 +715,6 @@ contract SecurityToken is StandardToken, DetailedERC20, ReentrancyGuard, Registr return currentCheckpointId; } - /** - * @notice Validate permissions with PermissionManager if it exists, If no Permission return false - * @dev Note that IModule withPerm will allow ST owner all permissions anyway - * @dev this allows individual modules to override this logic if needed (to not allow ST owner all permissions) - * @param _delegate address of delegate - * @param _module address of PermissionManager module - * @param _perm the permissions - * @return success - */ - function checkPermission(address _delegate, address _module, bytes32 _perm) public view returns(bool) { - if (modules[PERMISSIONMANAGER_KEY].length == 0) { - return false; - } - - for (uint8 i = 0; i < modules[PERMISSIONMANAGER_KEY].length; i++) { - if (IPermissionManager(modules[PERMISSIONMANAGER_KEY][i]).checkPermission(_delegate, _module, _perm)) { - return true; - } - } - } - /** * @notice Gets list of times that checkpoints were created * @return List of checkpoint times From 4d816664bd7810d27af19a689d07e68f99c4043b Mon Sep 17 00:00:00 2001 From: Pablo Ruiz Date: Tue, 2 Oct 2018 09:21:52 -0300 Subject: [PATCH 54/63] changed ganache test limit to 0xfffffffffff for coverage --- scripts/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test.sh b/scripts/test.sh index f6bb5ee03..d24ce6b0f 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -61,7 +61,7 @@ start_testrpc() { ) if ! [ -z "${TRAVIS_PULL_REQUEST+x}" ] && [ "$TRAVIS_PULL_REQUEST" != false ]; then - node_modules/.bin/testrpc-sc --gasLimit 8000000 --port "$testrpc_port" "${accounts[@]}" > /dev/null & + node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port "$testrpc_port" "${accounts[@]}" > /dev/null & else node_modules/.bin/ganache-cli --gasLimit 8000000 "${accounts[@]}" > /dev/null & fi From b7562242d37ce247876028368554a437de4203df Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 17:57:49 +0530 Subject: [PATCH 55/63] Removed hard-coded gas in some tests --- test/c_checkpoints.js | 2 +- test/d_count_transfer_manager.js | 2 +- test/e_erc20_dividends.js | 2 +- test/f_ether_dividends.js | 2 +- test/g_general_permission_manager.js | 2 +- test/j_manual_approval_transfer_manager.js | 2 +- test/k_module_registry.js | 4 ++-- test/l_percentage_transfer_manager.js | 2 +- test/m_presale_sto.js | 12 ++++++------ test/r_concurrent_STO.js | 2 +- test/t_security_token_registry_proxy.js | 2 +- test/v_tracked_redemptions.js | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/c_checkpoints.js b/test/c_checkpoints.js index d40996a66..a9094c6c5 100644 --- a/test/c_checkpoints.js +++ b/test/c_checkpoints.js @@ -205,7 +205,7 @@ contract('Checkpoints', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/d_count_transfer_manager.js b/test/d_count_transfer_manager.js index 4b65e249a..75c938939 100644 --- a/test/d_count_transfer_manager.js +++ b/test/d_count_transfer_manager.js @@ -247,7 +247,7 @@ contract('CountTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 82125d688..a8378cb8b 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -239,7 +239,7 @@ contract('ERC20DividendCheckpoint', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 0e7468075..c2441a299 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -239,7 +239,7 @@ contract('EtherDividendCheckpoint', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/g_general_permission_manager.js b/test/g_general_permission_manager.js index 6e483d203..3b7299ca2 100644 --- a/test/g_general_permission_manager.js +++ b/test/g_general_permission_manager.js @@ -254,7 +254,7 @@ contract('GeneralPermissionManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/j_manual_approval_transfer_manager.js b/test/j_manual_approval_transfer_manager.js index 78953fa24..9036435f8 100644 --- a/test/j_manual_approval_transfer_manager.js +++ b/test/j_manual_approval_transfer_manager.js @@ -255,7 +255,7 @@ contract('ManualApprovalTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner}); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/k_module_registry.js b/test/k_module_registry.js index bc728259f..a7ed18719 100644 --- a/test/k_module_registry.js +++ b/test/k_module_registry.js @@ -384,7 +384,7 @@ contract('ModuleRegistry', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken.addModule(I_CappedSTOFactory1.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); + const tx = await I_SecurityToken.addModule(I_CappedSTOFactory1.address, bytesSTO, 0, 0, { from: token_owner}); } catch(error) { errorThrown = true; console.log(` tx revert -> Module is un-verified`.grey); @@ -426,7 +426,7 @@ contract('ModuleRegistry', accounts => { endTime = startTime + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let tx = await I_MRProxied.registerModule(I_CappedSTOFactory2.address, { from: token_owner }); - tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner, gas: 60000000 }); + tx = await I_SecurityToken.addModule(I_CappedSTOFactory2.address, bytesSTO, 0, 0, { from: token_owner}); assert.equal(tx.logs[2].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal( diff --git a/test/l_percentage_transfer_manager.js b/test/l_percentage_transfer_manager.js index 92504c4c2..4e81888f4 100644 --- a/test/l_percentage_transfer_manager.js +++ b/test/l_percentage_transfer_manager.js @@ -249,7 +249,7 @@ contract('PercentageTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/m_presale_sto.js b/test/m_presale_sto.js index acc04642d..862885bcf 100644 --- a/test/m_presale_sto.js +++ b/test/m_presale_sto.js @@ -229,7 +229,7 @@ contract('PreSaleSTO', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -256,7 +256,7 @@ contract('PreSaleSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [0]); let errorThrown = false; try { - const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner }); } catch(error) { console.log(` tx revert -> Rate is ${0}. Test Passed Successfully`.grey); errorThrown = true; @@ -269,7 +269,7 @@ contract('PreSaleSTO', accounts => { endTime = latestTime() + duration.days(30); // Start time will be 5000 seconds more than the latest time let bytesSTO = encodeModuleCall(STOParameters, [endTime]); - const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken.addModule(I_PreSaleSTOFactory.address, bytesSTO, 0, 0, { from: token_owner }); assert.equal(tx.logs[2].args._type, stoKey, "PreSaleSTO doesn't get deployed"); assert.equal( @@ -333,7 +333,7 @@ contract('PreSaleSTO', accounts => { // Jump time await increaseTime(duration.days(1)); - await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_issuer, gas: 60000000}); + await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_issuer }); assert.equal( (await I_PreSaleSTO.getRaised.call(0)) @@ -350,7 +350,7 @@ contract('PreSaleSTO', accounts => { it("Should allocate the tokens -- failed due to msg.sender is not pre sale admin", async () => { let errorThrown = false; try { - await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_fundsReceiver, gas: 60000000}); + await I_PreSaleSTO.allocateTokens(account_investor1, web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether'), 0, {from: account_fundsReceiver }); } catch(error) { console.log(` tx revert -> msg.sender is not pre sale admin`.grey); errorThrown = true; @@ -392,7 +392,7 @@ contract('PreSaleSTO', accounts => { assert.equal(tx2.logs[0].args._investor, account_investor3, "Failed in adding the investor in whitelist"); - await I_PreSaleSTO.allocateTokensMulti([account_investor2, account_investor3], [web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether')], [0,0], [web3.utils.toWei('1000', 'ether'), web3.utils.toWei('1000', 'ether')], {from: account_issuer, gas: 60000000}); + await I_PreSaleSTO.allocateTokensMulti([account_investor2, account_investor3], [web3.utils.toWei('1', 'ether'), web3.utils.toWei('1', 'ether')], [0,0], [web3.utils.toWei('1000', 'ether'), web3.utils.toWei('1000', 'ether')], {from: account_issuer }); assert.equal( (await I_PreSaleSTO.getRaised.call(1)) diff --git a/test/r_concurrent_STO.js b/test/r_concurrent_STO.js index c86d53a43..f01a36436 100644 --- a/test/r_concurrent_STO.js +++ b/test/r_concurrent_STO.js @@ -239,7 +239,7 @@ contract('Concurrent STO', accounts => { await I_PolyToken.getTokens(initRegFee, account_issuer); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: account_issuer}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: account_issuer, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: account_issuer }); assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); I_SecurityToken = SecurityToken.at(tx.logs[1].args._securityTokenAddress); diff --git a/test/t_security_token_registry_proxy.js b/test/t_security_token_registry_proxy.js index 2dcafde5c..2666f7158 100644 --- a/test/t_security_token_registry_proxy.js +++ b/test/t_security_token_registry_proxy.js @@ -185,7 +185,7 @@ contract ("SecurityTokenRegistryProxy", accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); diff --git a/test/v_tracked_redemptions.js b/test/v_tracked_redemptions.js index fe03a8614..95f3303ae 100644 --- a/test/v_tracked_redemptions.js +++ b/test/v_tracked_redemptions.js @@ -227,7 +227,7 @@ contract('TrackedRedemption', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); From a15f2ef73ec5231d0251a2d00acbce1facc15631 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 18:06:10 +0530 Subject: [PATCH 56/63] Removed more gas amounts --- test/b_capped_sto.js | 18 +++++++++--------- test/h_general_transfer_manager.js | 2 +- test/n_security_token_registry.js | 20 ++++++++++---------- test/o_security_token.js | 8 ++++---- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/test/b_capped_sto.js b/test/b_capped_sto.js index 11a797933..ec216c637 100644 --- a/test/b_capped_sto.js +++ b/test/b_capped_sto.js @@ -258,7 +258,7 @@ contract('CappedSTO', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -298,7 +298,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, 0, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { console.log(` tx revert -> Rate is ${0}. Test Passed Successfully`.grey); errorThrown = true; @@ -315,7 +315,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, 0, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { console.log(`Tx Failed because of rate is ${0}. Test Passed Successfully`); errorThrown = true; @@ -328,7 +328,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [ Math.floor(Date.now()/1000 + 100000), Math.floor(Date.now()/1000 + 1000), cap, rate, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { errorThrown = true; console.log(` tx revert -> StartTime is greater than endTime. Test Passed Successfully`.grey); @@ -343,7 +343,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [ startTime, endTime, 0, rate, [E_fundRaiseType], account_fundsReceiver]); let errorThrown = false; try { - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch(error) { console.log(`Tx Failed because the Cap is equal to ${0}. Test Passed Successfully`); errorThrown = true; @@ -356,7 +356,7 @@ contract('CappedSTO', accounts => { startTime_ETH1 = latestTime() + duration.days(1); endTime_ETH1 = startTime_ETH1 + duration.days(30); let bytesSTO = encodeModuleCall(STOParameters, [startTime_ETH1, endTime_ETH1, cap, rate, [E_fundRaiseType], account_fundsReceiver]); - const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 45000000 }); + const tx = await I_SecurityToken_ETH.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); @@ -876,7 +876,7 @@ contract('CappedSTO', accounts => { it("POLY: Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(P_name, P_symbol, P_tokenDetails, false, { from: token_owner, gas:85000000 }); + let tx = await I_STRProxied.generateSecurityToken(P_name, P_symbol, P_tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, P_symbol, "SecurityToken doesn't get deployed"); @@ -904,7 +904,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime_POLY1, endTime_POLY1, P_cap, P_rate, [P_fundRaiseType], account_fundsReceiver]); - const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); @@ -1262,7 +1262,7 @@ contract('CappedSTO', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime_POLY2, endTime_POLY2, P_cap, P_rate, [P_fundRaiseType], account_fundsReceiver]); - const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 26000000 }); + const tx = await I_SecurityToken_POLY.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.hexToString(tx.logs[3].args._name),"CappedSTO","CappedSTOFactory module was not added"); diff --git a/test/h_general_transfer_manager.js b/test/h_general_transfer_manager.js index 190ab54ad..36eccdbb0 100644 --- a/test/h_general_transfer_manager.js +++ b/test/h_general_transfer_manager.js @@ -241,7 +241,7 @@ contract('GeneralTransferManager', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas: 85000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol.toUpperCase(), "SecurityToken doesn't get deployed"); diff --git a/test/n_security_token_registry.js b/test/n_security_token_registry.js index e51bea0bd..b622c4704 100644 --- a/test/n_security_token_registry.js +++ b/test/n_security_token_registry.js @@ -485,7 +485,7 @@ contract('SecurityTokenRegistry', accounts => { let errorThrown = false; await I_PolyToken.approve(I_STRProxied.address, 0, { from: token_owner}); try { - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> POLY allowance not provided for registration fee`.grey); errorThrown = true; @@ -499,7 +499,7 @@ contract('SecurityTokenRegistry', accounts => { await I_STRProxied.pause({ from: account_polymath}); await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); try { - await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> Registration is paused`.grey); errorThrown = true; @@ -512,7 +512,7 @@ contract('SecurityTokenRegistry', accounts => { let errorThrown = false; await I_STRProxied.unpause({ from: account_polymath}); try { - await I_STRProxied.generateSecurityToken(name, "", tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken(name, "", tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> Zero ticker length is not allowed`.grey); errorThrown = true; @@ -524,7 +524,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should fail to generate the securityToken -- Because name length is 0", async() => { let errorThrown = false; try { - await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> 0 name length is not allowed`.grey); errorThrown = true; @@ -536,7 +536,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should fail to generate the securityToken -- Because msg.sender is not the rightful owner of the ticker", async() => { let errorThrown = false; try { - await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: account_temp, gas:60000000 }); + await I_STRProxied.generateSecurityToken("", symbol, tokenDetails, false, { from: account_temp }); } catch(error) { console.log(` tx revert -> Because msg.sender is not the rightful owner of the ticker`.grey); errorThrown = true; @@ -547,7 +547,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -568,7 +568,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should fail to generate the SecurityToken when token is already deployed with the same symbol", async() => { let errorThrown = false; try { - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> Because ticker is already in use`.grey); errorThrown = true; @@ -608,7 +608,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should generate the new security token with version 2", async() => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name2, symbol2, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name2, symbol2, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol2, "SecurityToken doesn't get deployed"); @@ -1014,7 +1014,7 @@ contract('SecurityTokenRegistry', accounts => { let errorThrown = false; await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner}); try { - await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner, gas:60000000 }); + await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner }); } catch(error) { console.log(` tx revert -> failed because of old launch fee`.grey); errorThrown = true; @@ -1025,7 +1025,7 @@ contract('SecurityTokenRegistry', accounts => { it("Should launch the the securityToken", async() => { await I_PolyToken.approve(I_STRProxied.address, web3.utils.toWei("500"), { from: token_owner}); - let tx = await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken("Polymath", "POLY", tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, "POLY", "SecurityToken doesn't get deployed"); diff --git a/test/o_security_token.js b/test/o_security_token.js index caaade82c..1217c6c22 100644 --- a/test/o_security_token.js +++ b/test/o_security_token.js @@ -255,7 +255,7 @@ contract('SecurityToken', accounts => { it("Should generate the new security token with the same symbol as registered above", async () => { await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner }); let _blockNo = latestBlock(); - let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner, gas:60000000 }); + let tx = await I_STRProxied.generateSecurityToken(name, symbol, tokenDetails, false, { from: token_owner }); // Verify the successful generation of the security token assert.equal(tx.logs[1].args._ticker, symbol, "SecurityToken doesn't get deployed"); @@ -444,7 +444,7 @@ contract('SecurityToken', accounts => { let bytesSTO = encodeModuleCall(STOParameters, [startTime, endTime, cap, rate, fundRaiseType, account_fundsReceiver]); let errorThrown = false; try { - let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 60000000 }); + let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); } catch (error) { console.log(` tx revert -> not enough poly in contract`); errorThrown = true; @@ -461,7 +461,7 @@ contract('SecurityToken', accounts => { await I_PolyToken.transfer(I_SecurityToken.address, cappedSTOSetupCost, { from: token_owner}); let errorThrown = false; try { - let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, web3.utils.toWei("1000","ether"), 0, { from: token_owner, gas: 60000000 }); + let tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, web3.utils.toWei("1000","ether"), 0, { from: token_owner }); } catch (error) { console.log(` tx revert -> max cost too small`); errorThrown = true; @@ -478,7 +478,7 @@ contract('SecurityToken', accounts => { await I_PolyToken.getTokens(cappedSTOSetupCost, token_owner); await I_PolyToken.transfer(I_SecurityToken.address, cappedSTOSetupCost, { from: token_owner}); - const tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner, gas: 60000000 }); + const tx = await I_SecurityToken.addModule(I_CappedSTOFactory.address, bytesSTO, maxCost, 0, { from: token_owner }); assert.equal(tx.logs[3].args._type, stoKey, "CappedSTO doesn't get deployed"); assert.equal(web3.utils.toUtf8(tx.logs[3].args._name), "CappedSTO", "CappedSTOFactory module was not added"); From b6981b20075b233f3429ac15564e90739c169155 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Tue, 2 Oct 2018 09:41:53 -0300 Subject: [PATCH 57/63] CLI: Gas limit for estimation --- CLI/commands/common/common_functions.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CLI/commands/common/common_functions.js b/CLI/commands/common/common_functions.js index 07de69fec..dbf3aa8dd 100644 --- a/CLI/commands/common/common_functions.js +++ b/CLI/commands/common/common_functions.js @@ -50,7 +50,12 @@ module.exports = { sendTransaction: async function (from, action, gasPrice, value, factor) { if (typeof factor === 'undefined') factor = 1.2; + let block = await web3.eth.getBlock("latest"); + let networkGasLimit = block.gasLimit; + let gas = Math.round(factor * (await action.estimateGas({ from: from.address, value: value}))); + if (gas > networkGasLimit) gas = networkGasLimit; + console.log(chalk.black.bgYellowBright(`---- Transaction executed: ${action._method.name} - Gas limit provided: ${gas} ----`)); let nonce = await web3.eth.getTransactionCount(from.address); From ec34f027a1b63230e2feeabba0747de7af603f06 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 18:21:29 +0530 Subject: [PATCH 58/63] Renamed a function Renamed `_CallERC20DividendDepositedEvent` to `_emitERC20DividendDepositedEvent` --- contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol index 703a81128..e89e0a0d1 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol @@ -144,14 +144,14 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { dividends[dividends.length - 1].dividendExcluded[_excluded[j]] = true; } dividendTokens[dividendIndex] = _token; - _CallERC20DividendDepositedEvent(_checkpointId, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); + _emitERC20DividendDepositedEvent(_checkpointId, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); } /** * @notice emits the ERC20DividendDeposited event. - * Seperated into a different function to work around the Stack too deep error + * Seperated into a different function as a workaround for stack too deep error */ - function _CallERC20DividendDepositedEvent(uint256 _checkpointId, uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 currentSupply, uint256 dividendIndex, string _name) internal { + function _emitERC20DividendDepositedEvent(uint256 _checkpointId, uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 currentSupply, uint256 dividendIndex, string _name) internal { emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); } From 94495e31ea6839fbbbc948b67821aef79e817301 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 20:02:19 +0530 Subject: [PATCH 59/63] Name changed from string to bytes32 --- .../modules/Checkpoint/DividendCheckpoint.sol | 2 +- .../Checkpoint/ERC20DividendCheckpoint.sol | 15 ++++---- .../Checkpoint/EtherDividendCheckpoint.sol | 13 +++---- test/e_erc20_dividends.js | 34 ++++++++++++++++++- test/f_ether_dividends.js | 16 ++++++++- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/contracts/modules/Checkpoint/DividendCheckpoint.sol b/contracts/modules/Checkpoint/DividendCheckpoint.sol index 3842bf5df..fc70a9fde 100644 --- a/contracts/modules/Checkpoint/DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/DividendCheckpoint.sol @@ -29,7 +29,7 @@ contract DividendCheckpoint is ICheckpoint, Module { uint256 dividendWithheldReclaimed; mapping (address => bool) claimed; // List of addresses which have claimed dividend mapping (address => bool) dividendExcluded; // List of addresses which cannot claim dividends - string name; // Name/title - used for identification + bytes32 name; // Name/title - used for identification } // List of all dividends diff --git a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol index e89e0a0d1..60d84a41b 100644 --- a/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/ERC20DividendCheckpoint.sol @@ -12,7 +12,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { // Mapping to token address for each dividend mapping (uint256 => address) public dividendTokens; - event ERC20DividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, address indexed _token, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, string _name); + event ERC20DividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, address indexed _token, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, bytes32 indexed _name); event ERC20DividendClaimed(address indexed _payee, uint256 _dividendIndex, address indexed _token, uint256 _amount, uint256 _withheld); event ERC20DividendReclaimed(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _claimedAmount); event ERC20DividendWithholdingWithdrawn(address indexed _claimer, uint256 _dividendIndex, address indexed _token, uint256 _withheldAmount); @@ -35,7 +35,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { * @param _amount Amount of specified token for dividend * @param _name name/title for identification */ - function createDividend(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, string _name) external onlyOwner { + function createDividend(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, bytes32 _name) external onlyOwner { createDividendWithExclusions(_maturity, _expiry, _token, _amount, excluded, _name); } @@ -48,7 +48,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { * @param _checkpointId Checkpoint id from which to create dividends * @param _name name/title for identification */ - function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId, string _name) external onlyOwner { + function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 _checkpointId, bytes32 _name) external onlyOwner { _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, _checkpointId, excluded, _name); } @@ -61,7 +61,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { * @param _excluded List of addresses to exclude * @param _name name/title for identification */ - function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, address[] _excluded, string _name) public onlyOwner { + function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, address[] _excluded, bytes32 _name) public onlyOwner { uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _token, _amount, checkpointId, _excluded, _name); } @@ -83,7 +83,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { uint256 _amount, uint256 _checkpointId, address[] _excluded, - string _name + bytes32 _name ) public onlyOwner @@ -108,7 +108,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { uint256 _amount, uint256 _checkpointId, address[] _excluded, - string _name + bytes32 _name ) internal { @@ -119,6 +119,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { require(_token != address(0), "0x not valid token"); require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId(), "Invalid checkpoint"); require(IERC20(_token).transferFrom(msg.sender, address(this), _amount), "Unable to transfer tokens for dividend"); + require(_name[0] != 0); uint256 dividendIndex = dividends.length; uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); uint256 excludedSupply = 0; @@ -151,7 +152,7 @@ contract ERC20DividendCheckpoint is DividendCheckpoint { * @notice emits the ERC20DividendDeposited event. * Seperated into a different function as a workaround for stack too deep error */ - function _emitERC20DividendDepositedEvent(uint256 _checkpointId, uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 currentSupply, uint256 dividendIndex, string _name) internal { + function _emitERC20DividendDepositedEvent(uint256 _checkpointId, uint256 _maturity, uint256 _expiry, address _token, uint256 _amount, uint256 currentSupply, uint256 dividendIndex, bytes32 _name) internal { emit ERC20DividendDeposited(msg.sender, _checkpointId, now, _maturity, _expiry, _token, _amount, currentSupply, dividendIndex, _name); } diff --git a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol index 0a20ee7a3..d8ecb2e9a 100644 --- a/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol +++ b/contracts/modules/Checkpoint/EtherDividendCheckpoint.sol @@ -8,7 +8,7 @@ import "./DividendCheckpoint.sol"; contract EtherDividendCheckpoint is DividendCheckpoint { using SafeMath for uint256; - event EtherDividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, string _name); + event EtherDividendDeposited(address indexed _depositor, uint256 _checkpointId, uint256 _created, uint256 _maturity, uint256 _expiry, uint256 _amount, uint256 _totalSupply, uint256 _dividendIndex, bytes32 indexed _name); event EtherDividendClaimed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); event EtherDividendReclaimed(address indexed _claimer, uint256 _dividendIndex, uint256 _claimedAmount); event EtherDividendClaimFailed(address indexed _payee, uint256 _dividendIndex, uint256 _amount, uint256 _withheld); @@ -30,7 +30,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { * @param _expiry Time until dividend can no longer be paid, and can be reclaimed by issuer * @param _name name/title for identification */ - function createDividend(uint256 _maturity, uint256 _expiry, string _name) payable external onlyOwner { + function createDividend(uint256 _maturity, uint256 _expiry, bytes32 _name) payable external onlyOwner { createDividendWithExclusions(_maturity, _expiry, excluded, _name); } @@ -41,7 +41,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { * @param _checkpointId Id of the checkpoint from which to issue dividend * @param _name name/title for identification */ - function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, uint256 _checkpointId, string _name) payable external onlyOwner { + function createDividendWithCheckpoint(uint256 _maturity, uint256 _expiry, uint256 _checkpointId, bytes32 _name) payable external onlyOwner { _createDividendWithCheckpointAndExclusions(_maturity, _expiry, _checkpointId, excluded, _name); } @@ -52,7 +52,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { * @param _excluded List of addresses to exclude * @param _name name/title for identification */ - function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address[] _excluded, string _name) payable public onlyOwner { + function createDividendWithExclusions(uint256 _maturity, uint256 _expiry, address[] _excluded, bytes32 _name) payable public onlyOwner { uint256 checkpointId = ISecurityToken(securityToken).createCheckpoint(); _createDividendWithCheckpointAndExclusions(_maturity, _expiry, checkpointId, _excluded, _name); } @@ -70,7 +70,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { uint256 _expiry, uint256 _checkpointId, address[] _excluded, - string _name + bytes32 _name ) payable public @@ -92,7 +92,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { uint256 _expiry, uint256 _checkpointId, address[] _excluded, - string _name + bytes32 _name ) internal { @@ -101,6 +101,7 @@ contract EtherDividendCheckpoint is DividendCheckpoint { require(_expiry > now, "Expiry is in the past"); require(msg.value > 0, "No dividend sent"); require(_checkpointId <= ISecurityToken(securityToken).currentCheckpointId()); + require(_name[0] != 0); uint256 dividendIndex = dividends.length; uint256 currentSupply = ISecurityToken(securityToken).totalSupplyAt(_checkpointId); uint256 excludedSupply = 0; diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index dd90435b2..1cf3eb020 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -41,7 +41,7 @@ contract('ERC20DividendCheckpoint', accounts => { let expiryTime = toTime + duration.days(15); let message = "Transaction Should Fail!"; - let dividendName = "TestDividend"; + let dividendName = "0x546573744469766964656e640000000000000000000000000000000000000000"; // Contract Instance Declaration let I_GeneralPermissionManagerFactory; @@ -521,11 +521,43 @@ contract('ERC20DividendCheckpoint', accounts => { ); }); + it("Should not allow to create dividend without name", async() => { + let maturity = latestTime() + duration.days(1); + let expiry = latestTime() + duration.days(10); + await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); + await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let errorThrown = false; + try { + await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), '', {from: token_owner}); + } catch(error) { + console.log(` tx -> failed because dividend name is empty`.grey); + ensureException(error); + errorThrown = true; + } + assert.ok(errorThrown, message); + }); + it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); + let errorThrown = false; + try { + await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), '', {from: token_owner}); + } catch(error) { + console.log(` tx -> failed because dividend name is empty`.grey); + ensureException(error); + errorThrown = true; + } + assert.ok(errorThrown, message); + }); + + it("Create new dividend", async() => { + let maturity = latestTime() + duration.days(1); + let expiry = latestTime() + duration.days(10); + await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); + // approved in above test let tx = await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), dividendName, {from: token_owner}); assert.equal(tx.logs[0].args._checkpointId.toNumber(), 2, "Dividend should be created at checkpoint 1"); }); diff --git a/test/f_ether_dividends.js b/test/f_ether_dividends.js index 661f87ac9..dec4be72f 100644 --- a/test/f_ether_dividends.js +++ b/test/f_ether_dividends.js @@ -41,7 +41,7 @@ contract('EtherDividendCheckpoint', accounts => { let expiryTime = toTime + duration.days(15); let message = "Transaction Should Fail!"; - let dividendName = "TestDividend"; + let dividendName = "0x546573744469766964656e640000000000000000000000000000000000000000"; // Contract Instance Declaration let I_GeneralPermissionManagerFactory; @@ -406,6 +406,20 @@ contract('EtherDividendCheckpoint', accounts => { await I_EtherDividendCheckpoint.setWithholdingFixed([account_investor2], BigNumber(20*10**16), {from: token_owner}); }); + it("Should fail in creating the dividend", async() => { + let errorThrown = false; + let maturity = latestTime() + duration.days(1); + let expiry = latestTime() + duration.days(10); + try { + await I_EtherDividendCheckpoint.createDividend(maturity, expiry, '', {from: token_owner, value: web3.utils.toWei('1.5', 'ether')}); + } catch(error) { + console.log(` tx -> failed because dividend name is empty`.grey); + ensureException(error); + errorThrown = true; + } + assert.ok(errorThrown, message); + }); + it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); From 842760359bf1621a65c9e66fc03ff2cde1dc9c61 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Oct 2018 20:12:26 +0530 Subject: [PATCH 60/63] Removed duplicate test case --- test/e_erc20_dividends.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/test/e_erc20_dividends.js b/test/e_erc20_dividends.js index 1cf3eb020..cdd1fa98d 100644 --- a/test/e_erc20_dividends.js +++ b/test/e_erc20_dividends.js @@ -537,22 +537,6 @@ contract('ERC20DividendCheckpoint', accounts => { assert.ok(errorThrown, message); }); - it("Create new dividend", async() => { - let maturity = latestTime() + duration.days(1); - let expiry = latestTime() + duration.days(10); - await I_PolyToken.getTokens(web3.utils.toWei('1.5', 'ether'), token_owner); - await I_PolyToken.approve(I_ERC20DividendCheckpoint.address, web3.utils.toWei('1.5', 'ether'), {from: token_owner}); - let errorThrown = false; - try { - await I_ERC20DividendCheckpoint.createDividend(maturity, expiry, I_PolyToken.address, web3.utils.toWei('1.5', 'ether'), '', {from: token_owner}); - } catch(error) { - console.log(` tx -> failed because dividend name is empty`.grey); - ensureException(error); - errorThrown = true; - } - assert.ok(errorThrown, message); - }); - it("Create new dividend", async() => { let maturity = latestTime() + duration.days(1); let expiry = latestTime() + duration.days(10); From c2b8b060da3e75aa2e97bbd3660c196632b5df8d Mon Sep 17 00:00:00 2001 From: satyam Date: Tue, 2 Oct 2018 21:04:07 +0530 Subject: [PATCH 61/63] remove Log prefix from the oracles contract --- contracts/oracles/MakerDAOOracle.sol | 12 ++++++------ contracts/oracles/PolyOracle.sol | 22 +++++++++++----------- test/a_poly_oracle.js | 20 ++++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/contracts/oracles/MakerDAOOracle.sol b/contracts/oracles/MakerDAOOracle.sol index ab7795007..63d8b73cb 100644 --- a/contracts/oracles/MakerDAOOracle.sol +++ b/contracts/oracles/MakerDAOOracle.sol @@ -13,9 +13,9 @@ contract MakerDAOOracle is IOracle, Ownable { bool public manualOverride; uint256 public manualPrice; - event LogChangeMedianizer(address _newMedianizer, address _oldMedianizer, uint256 _now); - event LogSetManualPrice(uint256 _oldPrice, uint256 _newPrice, uint256 _time); - event LogSetManualOverride(bool _override, uint256 _time); + event ChangeMedianizer(address _newMedianizer, address _oldMedianizer, uint256 _now); + event SetManualPrice(uint256 _oldPrice, uint256 _newPrice, uint256 _time); + event SetManualOverride(bool _override, uint256 _time); /** * @notice Creates a new Maker based oracle @@ -35,7 +35,7 @@ contract MakerDAOOracle is IOracle, Ownable { */ function changeMedianier(address _medianizer) public onlyOwner { require(_medianizer != address(0), "0x not allowed"); - emit LogChangeMedianizer(_medianizer, medianizer, now); + emit ChangeMedianizer(_medianizer, medianizer, now); medianizer = _medianizer; } @@ -78,7 +78,7 @@ contract MakerDAOOracle is IOracle, Ownable { * @param _price Price to set */ function setManualPrice(uint256 _price) public onlyOwner { - emit LogSetManualPrice(manualPrice, _price, now); + emit SetManualPrice(manualPrice, _price, now); manualPrice = _price; } @@ -88,7 +88,7 @@ contract MakerDAOOracle is IOracle, Ownable { */ function setManualOverride(bool _override) public onlyOwner { manualOverride = _override; - emit LogSetManualOverride(_override, now); + emit SetManualOverride(_override, now); } } diff --git a/contracts/oracles/PolyOracle.sol b/contracts/oracles/PolyOracle.sol index e5328ea74..005d1677b 100644 --- a/contracts/oracles/PolyOracle.sol +++ b/contracts/oracles/PolyOracle.sol @@ -26,10 +26,10 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { bool public freezeOracle; - event LogPriceUpdated(uint256 _price, uint256 _oldPrice, bytes32 _queryId, uint256 _time); - event LogNewOraclizeQuery(uint256 _time, bytes32 _queryId, string _query); - event LogAdminSet(address _admin, bool _valid, uint256 _time); - event LogStalePriceUpdate(bytes32 _queryId, uint256 _time, string _result); + event PriceUpdated(uint256 _price, uint256 _oldPrice, bytes32 _queryId, uint256 _time); + event NewOraclizeQuery(uint256 _time, bytes32 _queryId, string _query); + event AdminSet(address _admin, bool _valid, uint256 _time); + event StalePriceUpdate(bytes32 _queryId, uint256 _time, string _result); modifier isAdminOrOwner { require(admin[msg.sender] || msg.sender == owner, "Address is not admin or owner"); @@ -55,7 +55,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { require(!ignoreRequestIds[_requestId], "Ignoring requestId"); if (requestIds[_requestId] < latestUpdate) { // Result is stale, probably because it was received out of order - emit LogStalePriceUpdate(_requestId, requestIds[_requestId], _result); + emit StalePriceUpdate(_requestId, requestIds[_requestId], _result); return; } require(requestIds[_requestId] >= latestUpdate, "Result is stale"); @@ -67,7 +67,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { require(newPOLYUSD >= POLYUSD.sub(bound), "Result is too small"); } latestUpdate = requestIds[_requestId]; - emit LogPriceUpdated(newPOLYUSD, POLYUSD, _requestId, latestUpdate); + emit PriceUpdated(newPOLYUSD, POLYUSD, _requestId, latestUpdate); POLYUSD = newPOLYUSD; } @@ -83,7 +83,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { requestId = oraclize_query(oracleQueryType, oracleURL, gasLimit); requestIds[requestId] = now; maximumScheduledUpdated = now; - emit LogNewOraclizeQuery(now, requestId, oracleURL); + emit NewOraclizeQuery(now, requestId, oracleURL); } else { require(oraclize_getPrice(oracleQueryType, gasLimit) * _times.length <= address(this).balance, "Insufficient Funds"); for (uint256 i = 0; i < _times.length; i++) { @@ -93,7 +93,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { if (maximumScheduledUpdated < requestIds[requestId]) { maximumScheduledUpdated = requestIds[requestId]; } - emit LogNewOraclizeQuery(_times[i], requestId, oracleURL); + emit NewOraclizeQuery(_times[i], requestId, oracleURL); } } if (latestScheduledUpdate < maximumScheduledUpdated) { @@ -117,7 +117,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { uint256 scheduledTime = _startTime + (i * _interval); requestId = oraclize_query(scheduledTime, oracleQueryType, oracleURL, gasLimit); requestIds[requestId] = scheduledTime; - emit LogNewOraclizeQuery(scheduledTime, requestId, oracleURL); + emit NewOraclizeQuery(scheduledTime, requestId, oracleURL); } if (latestScheduledUpdate < requestIds[requestId]) { latestScheduledUpdate = requestIds[requestId]; @@ -129,7 +129,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { * @param _price POLYUSD price */ function setPOLYUSD(uint256 _price) onlyOwner public { - emit LogPriceUpdated(_price, POLYUSD, 0, now); + emit PriceUpdated(_price, POLYUSD, 0, now); POLYUSD = _price; latestUpdate = now; } @@ -220,7 +220,7 @@ contract PolyOracle is usingOraclize, IOracle, Ownable { */ function setAdmin(address _admin, bool _valid) onlyOwner public { admin[_admin] = _valid; - emit LogAdminSet(_admin, _valid, now); + emit AdminSet(_admin, _valid, now); } /** diff --git a/test/a_poly_oracle.js b/test/a_poly_oracle.js index 9eb6c9b56..f727b4014 100644 --- a/test/a_poly_oracle.js +++ b/test/a_poly_oracle.js @@ -84,9 +84,9 @@ let requestIds = new Array(); let tx = await I_PolyOracle.schedulePriceUpdatesFixed([],{from: owner, value:web3.utils.toWei("1")}); assert.isAtMost(tx.logs[0].args._time.toNumber(), latestTime()); // await increaseTime(50); - const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 1); + const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 1); // const log = await logNewPriceWatcher; - assert.equal(logNewPriceWatcher.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(logNewPriceWatcher.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(logNewPriceWatcher.args._price, 'Price returned was null.') assert.equal(logNewPriceWatcher.args._oldPrice.toNumber(), 0); console.log('Success! Current price is: ' + logNewPriceWatcher.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY') @@ -107,9 +107,9 @@ let requestIds = new Array(); } // Wait for the callback to be invoked by oraclize and the event to be emitted - const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 2); + const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 2); const log = await logNewPriceWatcher; - assert.equal(log.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(log.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(log.args._price, 'Price returned was null.'); console.log('Success! Current price is: ' + log.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY') }); @@ -137,9 +137,9 @@ let requestIds = new Array(); assert.isAtMost(time.toNumber(), latestTime() + ((i + 1) * 30)); } // Wait for the callback to be invoked by oraclize and the event to be emitted - const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 2); + const logNewPriceWatcher = promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 2); const log = await logNewPriceWatcher; - assert.equal(log.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(log.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(log.args._price, 'Price returned was null.') console.log('Success! Current price is: ' + log.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY'); latestPrice = log.args._price; @@ -229,9 +229,9 @@ let requestIds = new Array(); assert.isAtMost(time.toNumber(), timeScheduling[i]); } - const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 2); + const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 2); - assert.equal(logNewPriceWatcher.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + assert.equal(logNewPriceWatcher.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(logNewPriceWatcher.args._price, 'Price returned was null.') console.log('Success! Current price is: ' + logNewPriceWatcher.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY'); // assert.isTrue(false); @@ -319,8 +319,8 @@ let requestIds = new Array(); let blockNo = latestBlock(); let tx = await I_PolyOracle.schedulePriceUpdatesFixed([],{from: owner, value:web3.utils.toWei("1")}); assert.isAtMost(tx.logs[0].args._time.toNumber(), latestTime()); - const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.LogPriceUpdated({ fromBlock: blockNo }), 1); - assert.equal(logNewPriceWatcher.event, 'LogPriceUpdated', 'LogPriceUpdated not emitted.') + const logNewPriceWatcher = await promisifyLogWatch(I_PolyOracle.PriceUpdated({ fromBlock: blockNo }), 1); + assert.equal(logNewPriceWatcher.event, 'PriceUpdated', 'PriceUpdated not emitted.') assert.isNotNull(logNewPriceWatcher.args._price, 'Price returned was null.') console.log('Success! Current price is: ' + logNewPriceWatcher.args._price.dividedBy(new BigNumber(10).pow(18)).toNumber() + ' USD/POLY'); // assert.isTrue(false); From 874b81b27c96d5214f71d724d5947e8374e520ac Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Tue, 2 Oct 2018 15:55:28 -0300 Subject: [PATCH 62/63] CLI: rename of getModulesByTypeAndToken function --- CLI/commands/helpers/contract_addresses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLI/commands/helpers/contract_addresses.js b/CLI/commands/helpers/contract_addresses.js index 60c2531ea..b6dca4eeb 100644 --- a/CLI/commands/helpers/contract_addresses.js +++ b/CLI/commands/helpers/contract_addresses.js @@ -79,7 +79,7 @@ module.exports = { }, getModuleFactoryAddressByName: async function(stAddress, moduleType, moduleName) { let moduleRegistry = await getModuleRegistry(); - let availableModules = await moduleRegistry.methods.getAvailableModulesOfType(moduleType, stAddress).call(); + let availableModules = await moduleRegistry.methods.getModulesByTypeAndToken(moduleType, stAddress).call(); let result = null; let counter = 0; From 96399a75668ef78225f9c372aeca8b8a2c737d1b Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Tue, 2 Oct 2018 15:55:43 -0300 Subject: [PATCH 63/63] CLI: Dividend name or title --- CLI/commands/dividends_manager.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index aeb81d818..a757b78ef 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -137,10 +137,11 @@ async function start_explorer(){ await taxHoldingMenu(); break; case 'Create dividends': - let dividend = readlineSync.question(`How much ${dividendsType} would you like to distribute to token holders?: `); + let divName = readlineSync.question(`Enter a name or title to indetify this dividend: `); + let dividend = readlineSync.question(`How much ${dividendsType} would you like to distribute to token holders?: `); await checkBalance(dividend); let checkpointId = currentCheckpoint == 0 ? 0 : await selectCheckpoint(true); // If there are no checkpoints, it must create a new one - await createDividends(dividend, checkpointId); + await createDividends(divName, dividend, checkpointId); break; case 'Explore account at checkpoint': let _address = readlineSync.question('Enter address to explore: '); @@ -316,7 +317,7 @@ async function taxHoldingMenu() { } } -async function createDividends(dividend, checkpointId) { +async function createDividends(name, dividend, checkpointId) { await addDividendsModule(); let time = Math.floor(Date.now()/1000); @@ -332,17 +333,17 @@ async function createDividends(dividend, checkpointId) { await common.sendTransaction(Issuer, approveAction, defaultGasPrice); if (checkpointId > 0) { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), checkpointId, excluded, web3.utils.toHex(name)); } } else { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend)); + createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, polyToken._address, web3.utils.toWei(dividend), excluded, web3.utils.toHex(name)); } } let receipt = await common.sendTransaction(Issuer, createDividendAction, defaultGasPrice); @@ -351,17 +352,17 @@ async function createDividends(dividend, checkpointId) { } else if (dividendsType == 'ETH') { if (checkpointId > 0) { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, checkpointId); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpoint(maturityTime, expiryTime, checkpointId, web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, checkpointId, excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithCheckpointAndExclusions(maturityTime, expiryTime, checkpointId, excluded, web3.utils.toHex(name)); } } else { if (useDefaultExcluded) { - createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime); + createDividendAction = currentDividendsModule.methods.createDividend(maturityTime, expiryTime, web3.utils.toHex(name)); } else { let excluded = getExcludedFromDataFile(); - createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, excluded); + createDividendAction = currentDividendsModule.methods.createDividendWithExclusions(maturityTime, expiryTime, excluded, web3.utils.toHex(name)); } } let receipt = await common.sendTransaction(Issuer, createDividendAction, defaultGasPrice, web3.utils.toWei(dividend)); @@ -543,7 +544,8 @@ async function selectDividend(filter) { if (dividends.length > 0) { let options = dividends.map(function(d) { - return `Created: ${moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')} + return `${web3.utils.toAscii(d.name)} + Created: ${moment.unix(d.created).format('MMMM Do YYYY, HH:mm:ss')} Maturity: ${moment.unix(d.maturity).format('MMMM Do YYYY, HH:mm:ss')} Expiry: ${moment.unix(d.expiry).format('MMMM Do YYYY, HH:mm:ss')} At checkpoint: ${d.checkpointId}