diff --git a/0 b/0 deleted file mode 100644 index e69de29bb..000000000 diff --git a/CLI/commands/common/common_functions.js b/CLI/commands/common/common_functions.js index 7a9195891..40665d514 100644 --- a/CLI/commands/common/common_functions.js +++ b/CLI/commands/common/common_functions.js @@ -158,8 +158,8 @@ module.exports = { }, splitIntoBatches: function (data, batchSize) { let allBatches = []; - for (let index = 0; index < data.length; index += batchSize) { - allBatches.push(data.slice(index, index + batchSize)); + for (let index = 0; index < data.length; index += parseInt(batchSize)) { + allBatches.push(data.slice(index, index + parseInt(batchSize))); } return allBatches; }, diff --git a/CLI/commands/transfer_manager.js b/CLI/commands/transfer_manager.js index 0216d36a2..39af92b78 100644 --- a/CLI/commands/transfer_manager.js +++ b/CLI/commands/transfer_manager.js @@ -23,9 +23,9 @@ const REVOKE_MANUAL_APPROVAL_DATA_CSV = `${__dirname}/../data/Transfer/MATM/revo const ADD_DAILY_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/add_daily_restriction_data.csv`; const MODIFY_DAILY_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/modify_daily_restriction_data.csv`; const REMOVE_DAILY_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/remove_daily_restriction_data.csv`; -const ADD_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/add_restriction_data.csv`; -const MODIFY_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/modify_restriction_data.csv`; -const REMOVE_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/remove_restriction_data.csv`; +const ADD_CUSTOM_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/add_custom_restriction_data.csv`; +const MODIFY_CUSTOM_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/modify_custom_restriction_data.csv`; +const REMOVE_CUSTOM_RESTRICTIONS_DATA_CSV = `${__dirname}/../data/Transfer/VRTM/remove_custom_restriction_data.csv`; const ADD_LOCKUP_DATA_CSV = `${__dirname}/../data/Transfer/LockupTM/add_lockup_data.csv`; const MODIFY_LOCKUP_DATA_CSV = `${__dirname}/../data/Transfer/LockupTM/modify_lockup_data.csv`; const DELETE_LOCKUP_DATA_CSV = `${__dirname}/../data/Transfer/LockupTM/delete_lockup_data.csv`; @@ -1481,6 +1481,23 @@ async function addInvestorsToBlacklistsInBatch() { } } +function makeBatchRequest(calls) { + let batch = new web3.BatchRequest(); + + let promises = calls.map(call => { + return new Promise((res, rej) => { + let req = call.request({ from: Issuer.address }, (err, data) => { + if (err) rej(err); + else res(data) + }); + batch.add(req) + }) + }) + batch.execute() + + return Promise.all(promises) +} + async function removeInvestorsFromBlacklistsInBatch() { let csvFilePath = readlineSync.question(`Enter the path for csv data file (${REMOVE_INVESTOR_BLACKLIST_DATA_CSV}): `, { defaultInput: REMOVE_INVESTOR_BLACKLIST_DATA_CSV @@ -1515,45 +1532,70 @@ async function removeInvestorsFromBlacklistsInBatch() { async function volumeRestrictionTM() { console.log('\n', chalk.blue(`Volume Restriction Transfer Manager at ${currentTransferManager.options.address}`, '\n')); - let defaultDailyRestriction = await currentTransferManager.methods.defaultDailyRestriction().call(); - let hasDefaultDailyRestriction = parseInt(defaultDailyRestriction.startTime) !== 0; - let defaultRestriction = await currentTransferManager.methods.defaultRestriction().call(); - let hasDefaultRestriction = parseInt(defaultRestriction.startTime) !== 0; + let globalDailyRestriction = await currentTransferManager.methods.defaultDailyRestriction().call(); + let hasGlobalDailyRestriction = parseInt(globalDailyRestriction.startTime) !== 0; + let globalCustomRestriction = await currentTransferManager.methods.defaultRestriction().call(); + let hasGlobalCustomRestriction = parseInt(globalCustomRestriction.startTime) !== 0; + + console.log(`- Default daily restriction: ${hasGlobalDailyRestriction ? '' : 'None'}`); + if (hasGlobalDailyRestriction) { + console.log(` Type: ${RESTRICTION_TYPES[globalDailyRestriction.typeOfRestriction]}`); + console.log(` Allowed tokens: ${globalDailyRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(globalDailyRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(globalDailyRestriction.allowedTokens)}%`}`); + console.log(` Start time: ${moment.unix(globalDailyRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); + console.log(` Rolling period: ${globalDailyRestriction.rollingPeriodInDays} days`); + console.log(` End time: ${moment.unix(globalDailyRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + } + console.log(`- Default custom restriction: ${hasGlobalCustomRestriction ? '' : 'None'}`); + if (hasGlobalCustomRestriction) { + console.log(` Type: ${RESTRICTION_TYPES[globalCustomRestriction.typeOfRestriction]}`); + console.log(` Allowed tokens: ${globalCustomRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(globalCustomRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(globalCustomRestriction.allowedTokens)}%`}`); + console.log(` Start time: ${moment.unix(globalCustomRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); + console.log(` Rolling period: ${globalCustomRestriction.rollingPeriodInDays} days`); + console.log(` End time: ${moment.unix(globalCustomRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + } + + let addressesAndRestrictions = await currentTransferManager.methods.getRestrictedData().call(); + console.log(`- Individual restrictions: ${addressesAndRestrictions.allAddresses.length}`); + let exemptedAddresses = await currentTransferManager.methods.getExemptAddress().call(); + console.log(`- Exempted addresses: ${exemptedAddresses.length}`); - console.log(`- Default daily restriction: ${hasDefaultDailyRestriction ? '' : 'None'}`); - if (hasDefaultDailyRestriction) { - console.log(` Type: ${RESTRICTION_TYPES[defaultDailyRestriction.typeOfRestriction]}`); - console.log(` Allowed tokens: ${defaultDailyRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(defaultDailyRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(defaultDailyRestriction.allowedTokens)}%`}`); - console.log(` Start time: ${moment.unix(defaultDailyRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); - console.log(` Rolling period: ${defaultDailyRestriction.rollingPeriodInDays} days`); - console.log(` End time: ${moment.unix(defaultDailyRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + let options = []; + if (addressesAndRestrictions.allAddresses.length > 0) { + options.push('Show restrictions'); } - console.log(`- Default restriction: ${hasDefaultRestriction ? '' : 'None'} `); - if (hasDefaultRestriction) { - console.log(` Type: ${RESTRICTION_TYPES[defaultRestriction.typeOfRestriction]}`); - console.log(` Allowed tokens: ${defaultRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(defaultRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(defaultRestriction.allowedTokens)}%`}`); - console.log(` Start time: ${moment.unix(defaultRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); - console.log(` Rolling period: ${defaultRestriction.rollingPeriodInDays} days`); - console.log(` End time: ${moment.unix(defaultRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + if (exemptedAddresses.length > 0) { + options.push('Show exempted addresses'); } - - let options = [ + options.push( 'Change exempt wallet', 'Change default restrictions', 'Change individual restrictions', 'Explore account', 'Operate with multiple restrictions' - ]; + ); let index = readlineSync.keyInSelect(options, 'What do you want to do?', { cancel: 'RETURN' }); let optionSelected = index !== -1 ? options[index] : 'RETURN'; console.log('Selected:', optionSelected, '\n'); switch (optionSelected) { + case 'Show restrictions': + showRestrictionTable( + addressesAndRestrictions.allAddresses, + addressesAndRestrictions.allowedTokens, + addressesAndRestrictions.typeOfRestriction, + addressesAndRestrictions.rollingPeriodInDays, + addressesAndRestrictions.startTime, + addressesAndRestrictions.endTime, + ); + break; + case 'Show exempted addresses': + showExemptedAddresses(exemptedAddresses); + break; case 'Change exempt wallet': await changeExemptWallet(); break; case 'Change default restrictions': - await changeDefaultRestrictions(hasDefaultDailyRestriction, hasDefaultRestriction); + await changeDefaultRestrictions(hasGlobalDailyRestriction, hasGlobalCustomRestriction); break; case 'Change individual restrictions': await changeIndividualRestrictions(); @@ -1571,6 +1613,26 @@ async function volumeRestrictionTM() { await volumeRestrictionTM(); } +function showRestrictionTable(investorArray, amountArray, typeArray, rollingPeriodArray, startTimeArray, endTimeTimeArray) { + let dataTable = [['Investor', 'Maximum transfer (# or %)', 'Rolling period (days)', 'Start date', 'End date']]; + for (let i = 0; i < investorArray.length; i++) { + dataTable.push([ + investorArray[i], + typeArray[i] === "0" ? `${web3.utils.fromWei(amountArray[i])} ${tokenSymbol}` : `${fromWeiPercentage(amountArray[i])}%`, + rollingPeriodArray[i], + moment.unix(startTimeArray[i]).format('MM/DD/YYYY HH:mm'), + moment.unix(endTimeTimeArray[i]).format('MM/DD/YYYY HH:mm') + ]); + } + console.log(); + console.log(table(dataTable)); +} + +function showExemptedAddresses(addresses) { + console.log("*********** Exepmpted addresses ***********"); + addresses.map(i => console.log(i)); +} + async function changeExemptWallet() { let options = [ 'Add exempt wallet', @@ -1604,85 +1666,85 @@ async function changeExemptWallet() { console.log(chalk.green(`${changeExemptWalletEvent._wallet} has been ${changeExemptWalletEvent._change ? `added to` : `removed from`} exempt wallets successfully!`)); } -async function changeDefaultRestrictions(hasDefaultDailyRestriction, hasDefaultRestriction) { +async function changeDefaultRestrictions(hasGlobalDailyRestriction, hasGlobalCustomRestriction) { let options = []; - if (!hasDefaultDailyRestriction) { - options.push('Add default daily restriction'); + if (!hasGlobalDailyRestriction) { + options.push('Add global daily restriction'); } else { - options.push('Modify default daily restriction', 'Remove default daily restriction'); + options.push('Modify global daily restriction', 'Remove global daily restriction'); } - if (!hasDefaultRestriction) { - options.push('Add default restriction'); + if (!hasGlobalCustomRestriction) { + options.push('Add global custom restriction'); } else { - options.push('Modify default restriction', 'Remove default restriction'); + options.push('Modify global custom restriction', 'Remove global custom restriction'); } let index = readlineSync.keyInSelect(options, 'What do you want to do?', { cancel: 'RETURN' }); let optionSelected = index !== -1 ? options[index] : 'RETURN'; console.log('Selected:', optionSelected, '\n'); switch (optionSelected) { - case 'Add default daily restriction': - let defaultDailyRestrictoToAdd = inputRestrictionData(true); - let addDefaultDailyRestrictionAction = currentTransferManager.methods.addDefaultDailyRestriction( - defaultDailyRestrictoToAdd.allowedTokens, - defaultDailyRestrictoToAdd.startTime, - defaultDailyRestrictoToAdd.endTime, - defaultDailyRestrictoToAdd.restrictionType + case 'Add global daily restriction': + let globalDailyRestrictoToAdd = inputRestrictionData(true); + let addGlobalDailyRestrictionAction = currentTransferManager.methods.addDefaultDailyRestriction( + globalDailyRestrictoToAdd.allowedTokens, + globalDailyRestrictoToAdd.startTime, + globalDailyRestrictoToAdd.endTime, + globalDailyRestrictoToAdd.restrictionType ); - let addDefaultDailyRestrictionReceipt = await common.sendTransaction(addDefaultDailyRestrictionAction); - let addDefaultDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addDefaultDailyRestrictionReceipt.logs, 'AddDefaultDailyRestriction'); - console.log(chalk.green(`Daily default restriction has been added successfully!`)); - break; - case 'Modify default daily restriction': - let defaultDailyRestrictoToModify = inputRestrictionData(true); - let modifyDefaultDailyRestrictionAction = currentTransferManager.methods.modifyDefaultDailyRestriction( - defaultDailyRestrictoToModify.allowedTokens, - defaultDailyRestrictoToModify.startTime, - defaultDailyRestrictoToModify.endTime, - defaultDailyRestrictoToModify.restrictionType + let addGlobalDailyRestrictionReceipt = await common.sendTransaction(addGlobalDailyRestrictionAction); + let addGlobalDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addGlobalDailyRestrictionReceipt.logs, 'AddDefaultDailyRestriction'); + console.log(chalk.green(`Global daily restriction has been added successfully!`)); + break; + case 'Modify global daily restriction': + let globalDailyRestrictoToModify = inputRestrictionData(true); + let modifyGlobalDailyRestrictionAction = currentTransferManager.methods.modifyDefaultDailyRestriction( + globalDailyRestrictoToModify.allowedTokens, + globalDailyRestrictoToModify.startTime, + globalDailyRestrictoToModify.endTime, + globalDailyRestrictoToModify.restrictionType ); - let modifyDefaultDailyRestrictionReceipt = await common.sendTransaction(modifyDefaultDailyRestrictionAction); - let modifyDefaultDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyDefaultDailyRestrictionReceipt.logs, 'ModifyDefaultDailyRestriction'); - console.log(chalk.green(`Daily default restriction has been modified successfully!`)); - break; - case 'Remove default daily restriction': - let removeDefaultDailyRestrictionAction = currentTransferManager.methods.removeDefaultDailyRestriction(); - let removeDefaultDailyRestrictionReceipt = await common.sendTransaction(removeDefaultDailyRestrictionAction); - let removeDefaultDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeDefaultDailyRestrictionReceipt.logs, 'DefaultDailyRestrictionRemoved'); - console.log(chalk.green(`Daily default restriction has been removed successfully!`)); - break; - case 'Add default restriction': - let defaultRestrictoToAdd = inputRestrictionData(false); - let addDefaultRestrictionAction = currentTransferManager.methods.addDefaultRestriction( - defaultRestrictoToAdd.allowedTokens, - defaultRestrictoToAdd.startTime, - defaultRestrictoToAdd.rollingPeriodInDays, - defaultRestrictoToAdd.endTime, - defaultRestrictoToAdd.restrictionType + let modifyGlobalDailyRestrictionReceipt = await common.sendTransaction(modifyGlobalDailyRestrictionAction); + let modifyGlobalDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyGlobalDailyRestrictionReceipt.logs, 'ModifyDefaultDailyRestriction'); + console.log(chalk.green(`Global daily restriction has been modified successfully!`)); + break; + case 'Remove global daily restriction': + let removeGlobalDailyRestrictionAction = currentTransferManager.methods.removeDefaultDailyRestriction(); + let removeGlobalDailyRestrictionReceipt = await common.sendTransaction(removeGlobalDailyRestrictionAction); + let removeGlobalDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeGlobalDailyRestrictionReceipt.logs, 'DefaultDailyRestrictionRemoved'); + console.log(chalk.green(`Global daily restriction has been removed successfully!`)); + break; + case 'Add global custom restriction': + let globalCustomRestrictoToAdd = inputRestrictionData(false); + let addGlobalCustomRestrictionAction = currentTransferManager.methods.addDefaultRestriction( + globalCustomRestrictoToAdd.allowedTokens, + globalCustomRestrictoToAdd.startTime, + globalCustomRestrictoToAdd.rollingPeriodInDays, + globalCustomRestrictoToAdd.endTime, + globalCustomRestrictoToAdd.restrictionType ); - let addDefaultRestrictionReceipt = await common.sendTransaction(addDefaultRestrictionAction); - let addDefaultRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addDefaultRestrictionReceipt.logs, 'AddDefaultRestriction'); - console.log(chalk.green(`Default restriction has been added successfully!`)); - break; - case 'Modify default restriction': - let defaultRestrictoToModify = inputRestrictionData(false); - let modifyDefaultRestrictionAction = currentTransferManager.methods.modifyDefaultRestriction( - defaultRestrictoToModify.allowedTokens, - defaultRestrictoToModify.startTime, - defaultRestrictoToModify.rollingPeriodInDays, - defaultRestrictoToModify.endTime, - defaultRestrictoToModify.restrictionType + let addGlobalCustomRestrictionReceipt = await common.sendTransaction(addGlobalCustomRestrictionAction); + let addGlobalCustomRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addGlobalCustomRestrictionReceipt.logs, 'AddDefaultRestriction'); + console.log(chalk.green(`Global custom restriction has been added successfully!`)); + break; + case 'Modify global custom restriction': + let globalCustomRestrictoToModify = inputRestrictionData(false); + let modifiyGlobalCustomRestrictionAction = currentTransferManager.methods.modifyDefaultRestriction( + globalCustomRestrictoToModify.allowedTokens, + globalCustomRestrictoToModify.startTime, + globalCustomRestrictoToModify.rollingPeriodInDays, + globalCustomRestrictoToModify.endTime, + globalCustomRestrictoToModify.restrictionType ); - let modifyDefaultRestrictionReceipt = await common.sendTransaction(modifyDefaultRestrictionAction); - let modifyDefaultRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyDefaultRestrictionReceipt.logs, 'ModifyDefaultRestriction'); - console.log(chalk.green(`Default restriction has been modified successfully!`)); + let modifyGlobalCustomRestrictionReceipt = await common.sendTransaction(modifiyGlobalCustomRestrictionAction); + let modifyGlobalCustomRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyGlobalCustomRestrictionReceipt.logs, 'ModifyDefaultRestriction'); + console.log(chalk.green(`Global custom restriction has been modified successfully!`)); break; - case 'Remove default restriction': - let removeDefaultRestrictionAction = currentTransferManager.methods.removeDefaultRestriction(); - let removeDefaultRestrictionReceipt = await common.sendTransaction(removeDefaultRestrictionAction); - let removeDefaultRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeDefaultRestrictionReceipt.logs, 'DefaultRestrictionRemoved'); - console.log(chalk.green(`Default restriction has been removed successfully!`)); + case 'Remove global custom restriction': + let removeGlobalCustomRestrictionAction = currentTransferManager.methods.removeDefaultRestriction(); + let removeGlobalCustomRestrictionReceipt = await common.sendTransaction(removeGlobalCustomRestrictionAction); + let removeGlobalCustomRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeGlobalCustomRestrictionReceipt.logs, 'DefaultRestrictionRemoved'); + console.log(chalk.green(`Global custom restriction has been removed successfully!`)); break; } } @@ -1697,12 +1759,12 @@ async function changeIndividualRestrictions() { let currentDailyRestriction = await currentTransferManager.methods.individualDailyRestriction(holder).call(); let hasDailyRestriction = parseInt(currentDailyRestriction.startTime) !== 0; - let currentRestriction = await currentTransferManager.methods.individualRestriction(holder).call(); - let hasRestriction = parseInt(currentRestriction.startTime) !== 0; + let currentCustomRestriction = await currentTransferManager.methods.individualRestriction(holder).call(); + let hasCustomRestriction = parseInt(currentCustomRestriction.startTime) !== 0; console.log(`*** Current individual restrictions for ${holder} ***`, '\n'); - console.log(`- Daily restriction: ${hasDailyRestriction ? '' : 'None'}`); + console.log(`- Daily restriction: ${hasDailyRestriction ? '' : 'None'}`); if (hasDailyRestriction) { console.log(` Type: ${RESTRICTION_TYPES[currentDailyRestriction.typeOfRestriction]}`); console.log(` Allowed tokens: ${currentDailyRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(currentDailyRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(currentDailyRestriction.allowedTokens)}%`}`); @@ -1710,13 +1772,13 @@ async function changeIndividualRestrictions() { console.log(` Rolling period: ${currentDailyRestriction.rollingPeriodInDays} days`); console.log(` End time: ${moment.unix(currentDailyRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); } - console.log(`- Other restriction: ${hasRestriction ? '' : 'None'} `); - if (hasRestriction) { - console.log(` Type: ${RESTRICTION_TYPES[currentRestriction.typeOfRestriction]}`); - console.log(` Allowed tokens: ${currentRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(currentRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(currentRestriction.allowedTokens)}%`}`); - console.log(` Start time: ${moment.unix(currentRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); - console.log(` Rolling period: ${currentRestriction.rollingPeriodInDays} days`); - console.log(` End time: ${moment.unix(currentRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + console.log(`- Custom restriction: ${hasCustomRestriction ? '' : 'None'} `); + if (hasCustomRestriction) { + console.log(` Type: ${RESTRICTION_TYPES[currentCustomRestriction.typeOfRestriction]}`); + console.log(` Allowed tokens: ${currentCustomRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(currentCustomRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(currentCustomRestriction.allowedTokens)}%`}`); + console.log(` Start time: ${moment.unix(currentCustomRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); + console.log(` Rolling period: ${currentCustomRestriction.rollingPeriodInDays} days`); + console.log(` End time: ${moment.unix(currentCustomRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); } let options = []; @@ -1726,10 +1788,10 @@ async function changeIndividualRestrictions() { options.push('Modify individual daily restriction', 'Remove individual daily restriction'); } - if (!hasRestriction) { - options.push('Add individual restriction'); + if (!hasCustomRestriction) { + options.push('Add individual custom restriction'); } else { - options.push('Modify individual restriction', 'Remove individual restriction'); + options.push('Modify individual custom restriction', 'Remove individual custom restriction'); } let index = readlineSync.keyInSelect(options, 'What do you want to do?', { cancel: 'RETURN' }); @@ -1737,26 +1799,26 @@ async function changeIndividualRestrictions() { console.log('Selected:', optionSelected, '\n'); switch (optionSelected) { case 'Add individual daily restriction': - let dailyRestrictoToAdd = inputRestrictionData(true); + let dailyRestrictonToAdd = inputRestrictionData(true); let addDailyRestrictionAction = currentTransferManager.methods.addIndividualDailyRestriction( holder, - dailyRestrictoToAdd.allowedTokens, - dailyRestrictoToAdd.startTime, - dailyRestrictoToAdd.endTime, - dailyRestrictoToAdd.restrictionType + dailyRestrictonToAdd.allowedTokens, + dailyRestrictonToAdd.startTime, + dailyRestrictonToAdd.endTime, + dailyRestrictonToAdd.restrictionType ); let addDailyRestrictionReceipt = await common.sendTransaction(addDailyRestrictionAction); let addDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addDailyRestrictionReceipt.logs, 'AddIndividualDailyRestriction'); console.log(chalk.green(`Daily restriction for ${addDailyRestrictionEvent._holder} has been added successfully!`)); break; case 'Modify individual daily restriction': - let dailyRestrictoToModify = inputRestrictionData(true); + let dailyRestrictonToModify = inputRestrictionData(true); let modifyDailyRestrictionAction = currentTransferManager.methods.modifyIndividualDailyRestriction( holder, - dailyRestrictoToModify.allowedTokens, - dailyRestrictoToModify.startTime, - dailyRestrictoToModify.endTime, - dailyRestrictoToModify.restrictionType + dailyRestrictonToModify.allowedTokens, + dailyRestrictonToModify.startTime, + dailyRestrictonToModify.endTime, + dailyRestrictonToModify.restrictionType ); let modifyDailyRestrictionReceipt = await common.sendTransaction(modifyDailyRestrictionAction); let modifyDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyDailyRestrictionReceipt.logs, 'ModifyIndividualDailyRestriction'); @@ -1768,39 +1830,39 @@ async function changeIndividualRestrictions() { let removeDailyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeDailyRestrictionReceipt.logs, 'IndividualDailyRestrictionRemoved'); console.log(chalk.green(`Daily restriction for ${removeDailyRestrictionEvent._holder} has been removed successfully!`)); break; - case 'Add individual restriction': - let restrictoToAdd = inputRestrictionData(false); - let addRestrictionAction = currentTransferManager.methods.addIndividualRestriction( + case 'Add individual custom restriction': + let restrictonToAdd = inputRestrictionData(false); + let addCustomRestrictionAction = currentTransferManager.methods.addIndividualRestriction( holder, - restrictoToAdd.allowedTokens, - restrictoToAdd.startTime, - restrictoToAdd.rollingPeriodInDays, - restrictoToAdd.endTime, - restrictoToAdd.restrictionType + restrictonToAdd.allowedTokens, + restrictonToAdd.startTime, + restrictonToAdd.rollingPeriodInDays, + restrictonToAdd.endTime, + restrictonToAdd.restrictionType ); - let addRestrictionReceipt = await common.sendTransaction(addRestrictionAction); - let addRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addRestrictionReceipt.logs, 'AddIndividualRestriction'); - console.log(chalk.green(`Restriction for ${addRestrictionEvent._holder} has been added successfully!`)); + let addCustomRestrictionReceipt = await common.sendTransaction(addCustomRestrictionAction); + let addCustomRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, addCustomRestrictionReceipt.logs, 'AddIndividualRestriction'); + console.log(chalk.green(`Custom restriction for ${addCustomRestrictionEvent._holder} has been added successfully!`)); break; - case 'Modify individual restriction': - let restrictoToModify = inputRestrictionData(false); - let modifyRestrictionAction = currentTransferManager.methods.modifyIndividualRestriction( + case 'Modify individual custom restriction': + let restrictonToModify = inputRestrictionData(false); + let modifyCustomRestrictionAction = currentTransferManager.methods.modifyIndividualRestriction( holder, - restrictoToModify.allowedTokens, - restrictoToModify.startTime, - restrictoToModify.rollingPeriodInDays, - restrictoToModify.endTime, - restrictoToModify.restrictionType + restrictonToModify.allowedTokens, + restrictonToModify.startTime, + restrictonToModify.rollingPeriodInDays, + restrictonToModify.endTime, + restrictonToModify.restrictionType ); - let modifyRestrictionReceipt = await common.sendTransaction(modifyRestrictionAction); - let modifyRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyRestrictionReceipt.logs, 'ModifyIndividualRestriction'); - console.log(chalk.green(`Restriction for ${modifyRestrictionEvent._holder} has been modified successfully!`)); + let modifyCustomRestrictionReceipt = await common.sendTransaction(modifyCustomRestrictionAction); + let modifyCustomRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyCustomRestrictionReceipt.logs, 'ModifyIndividualRestriction'); + console.log(chalk.green(`Custom restriction for ${modifyCustomRestrictionEvent._holder} has been modified successfully!`)); break; - case 'Remove individual restriction': - let removeRestrictionAction = currentTransferManager.methods.removeIndividualRestriction(holder); - let removeRestrictionReceipt = await common.sendTransaction(removeRestrictionAction); - let removeRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeRestrictionReceipt.logs, 'IndividualRestrictionRemoved'); - console.log(chalk.green(`Restriction for ${removeRestrictionEvent._holder} has been removed successfully!`)); + case 'Remove individual custom restriction': + let removeCustomRestrictionAction = currentTransferManager.methods.removeIndividualRestriction(holder); + let removeCustomRestrictionReceipt = await common.sendTransaction(removeCustomRestrictionAction); + let removeCustomRestrictionEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, removeCustomRestrictionReceipt.logs, 'IndividualRestrictionRemoved'); + console.log(chalk.green(`Custom restriction for ${removeCustomRestrictionEvent._holder} has been removed successfully!`)); break; case 'RETURN': return; @@ -1815,54 +1877,54 @@ async function exploreAccount() { limitMessage: "Must be a valid address" }); - let appliyngdDailyRestriction = null; - let applyingOtherRestriction = null; + let appliyngDailyRestriction = null; + let applyingCustomRestriction = null; let hasIndividualRestrictions = false; let isExempted = await currentTransferManager.methods.exemptList(account).call(); if (!isExempted) { - let indiviaulDailyRestriction = await currentTransferManager.methods.individualDailyRestriction(account).call(); - if (parseInt(indiviaulDailyRestriction.endTime) !== 0) { - appliyngdDailyRestriction = indiviaulDailyRestriction; + let individuallDailyRestriction = await currentTransferManager.methods.individualDailyRestriction(account).call(); + if (parseInt(individuallDailyRestriction.endTime) !== 0) { + appliyngDailyRestriction = individuallDailyRestriction; } - let otherRestriction = await currentTransferManager.methods.individualRestriction(account).call(); - if (parseInt(otherRestriction.endTime) !== 0) { - applyingOtherRestriction = otherRestriction; + let customRestriction = await currentTransferManager.methods.individualRestriction(account).call(); + if (parseInt(customRestriction.endTime) !== 0) { + applyingCustomRestriction = customRestriction; } - hasIndividualRestrictions = applyingOtherRestriction || appliyngdDailyRestriction; + hasIndividualRestrictions = applyingCustomRestriction || appliyngDailyRestriction; if (!hasIndividualRestrictions) { - let defaultDailyRestriction = await currentTransferManager.methods.defaultDailyRestriction().call(); - if (parseInt(defaultDailyRestriction.endTime) !== 0) { - appliyngdDailyRestriction = defaultDailyRestriction; + let globalDailyRestriction = await currentTransferManager.methods.defaultDailyRestriction().call(); + if (parseInt(globalDailyRestriction.endTime) !== 0) { + appliyngDailyRestriction = globalDailyRestriction; } - let defaultOtherRestriction = await currentTransferManager.methods.defaultRestriction().call(); - if (parseInt(defaultOtherRestriction.endTime) === 0) { - applyingOtherRestriction = defaultOtherRestriction; + let globalCustomRestriction = await currentTransferManager.methods.defaultRestriction().call(); + if (parseInt(globalCustomRestriction.endTime) === 0) { + applyingCustomRestriction = globalCustomRestriction; } } } console.log(`*** Applying restrictions for ${account} ***`, '\n'); - console.log(`- Daily restriction: ${appliyngdDailyRestriction ? (!hasIndividualRestrictions ? 'default' : '') : 'None'}`); - if (appliyngdDailyRestriction) { - console.log(` Type: ${RESTRICTION_TYPES[appliyngdDailyRestriction.typeOfRestriction]}`); - console.log(` Allowed tokens: ${appliyngdDailyRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(appliyngdDailyRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(appliyngdDailyRestriction.allowedTokens)}%`}`); - console.log(` Start time: ${moment.unix(appliyngdDailyRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); - console.log(` Rolling period: ${appliyngdDailyRestriction.rollingPeriodInDays} days`); - console.log(` End time: ${moment.unix(appliyngdDailyRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + console.log(`- Daily restriction: ${appliyngDailyRestriction ? (!hasIndividualRestrictions ? 'global' : '') : 'None'}`); + if (appliyngDailyRestriction) { + console.log(` Type: ${RESTRICTION_TYPES[appliyngDailyRestriction.typeOfRestriction]}`); + console.log(` Allowed tokens: ${appliyngDailyRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(appliyngDailyRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(appliyngDailyRestriction.allowedTokens)}%`}`); + console.log(` Start time: ${moment.unix(appliyngDailyRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); + console.log(` Rolling period: ${appliyngDailyRestriction.rollingPeriodInDays} days`); + console.log(` End time: ${moment.unix(appliyngDailyRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); } - console.log(`- Other restriction: ${applyingOtherRestriction ? (!hasIndividualRestrictions ? 'default' : '') : 'None'} `); - if (applyingOtherRestriction) { - console.log(` Type: ${RESTRICTION_TYPES[applyingOtherRestriction.typeOfRestriction]}`); - console.log(` Allowed tokens: ${applyingOtherRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(applyingOtherRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(applyingOtherRestriction.allowedTokens)}%`}`); - console.log(` Start time: ${moment.unix(applyingOtherRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); - console.log(` Rolling period: ${applyingOtherRestriction.rollingPeriodInDays} days`); - console.log(` End time: ${moment.unix(applyingOtherRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); + console.log(`- Other restriction: ${applyingCustomRestriction ? (!hasIndividualRestrictions ? 'global' : '') : 'None'} `); + if (applyingCustomRestriction) { + console.log(` Type: ${RESTRICTION_TYPES[applyingCustomRestriction.typeOfRestriction]}`); + console.log(` Allowed tokens: ${applyingCustomRestriction.typeOfRestriction === "0" ? `${web3.utils.fromWei(applyingCustomRestriction.allowedTokens)} ${tokenSymbol}` : `${fromWeiPercentage(applyingCustomRestriction.allowedTokens)}%`}`); + console.log(` Start time: ${moment.unix(applyingCustomRestriction.startTime).format('MMMM Do YYYY, HH:mm:ss')}`); + console.log(` Rolling period: ${applyingCustomRestriction.rollingPeriodInDays} days`); + console.log(` End time: ${moment.unix(applyingCustomRestriction.endTime).format('MMMM Do YYYY, HH:mm:ss')} `); } - if (applyingOtherRestriction || appliyngdDailyRestriction) { + if (applyingCustomRestriction || appliyngDailyRestriction) { let bucketDetails; if (hasIndividualRestrictions) { bucketDetails = await currentTransferManager.methods.getIndividualBucketDetailsToUser(account).call(); @@ -1905,13 +1967,13 @@ async function operateWithMultipleRestrictions() { await removeDailyRestrictionsInBatch(); break; case 'Add multiple individual restrictions': - await addRestrictionsInBatch(); + await addCustomRestrictionsInBatch(); break; case 'Modify multiple individual restrictions': - await modifyRestrictionsInBatch(); + await modifyCustomRestrictionsInBatch(); break; case 'Remove multiple individual restrictions': - await removeRestrictionsInBatch(); + await removeCustomRestrictionsInBatch(); break; } } @@ -2014,9 +2076,9 @@ async function removeDailyRestrictionsInBatch() { } } -async function addRestrictionsInBatch() { - let csvFilePath = readlineSync.question(`Enter the path for csv data file (${ADD_RESTRICTIONS_DATA_CSV}): `, { - defaultInput: ADD_RESTRICTIONS_DATA_CSV +async function addCustomRestrictionsInBatch() { + let csvFilePath = readlineSync.question(`Enter the path for csv data file (${ADD_CUSTOM_RESTRICTIONS_DATA_CSV}): `, { + defaultInput: ADD_CUSTOM_RESTRICTIONS_DATA_CSV }); let batchSize = readlineSync.question(`Enter the max number of records per transaction or batch size (${gbl.constants.DEFAULT_BATCH_SIZE}): `, { limit: function (input) { @@ -2040,19 +2102,19 @@ async function addRestrictionsInBatch() { let batches = common.splitIntoBatches(validData, batchSize); let [holderArray, allowanceArray, startTimeArray, rollingPeriodArray, endTimeArray, restrictionTypeArray] = common.transposeBatches(batches); for (let batch = 0; batch < batches.length; batch++) { - console.log(`Batch ${batch + 1} - Attempting to add restrictions to the following accounts: \n\n`, holderArray[batch], '\n'); + console.log(`Batch ${batch + 1} - Attempting to add custom restrictions to the following accounts: \n\n`, holderArray[batch], '\n'); allowanceArray[batch] = allowanceArray[batch].map(n => web3.utils.toWei(n.toString())); restrictionTypeArray[batch] = restrictionTypeArray[batch].map(n => RESTRICTION_TYPES.indexOf(n)); let action = currentTransferManager.methods.addIndividualRestrictionMulti(holderArray[batch], allowanceArray[batch], startTimeArray[batch], rollingPeriodArray[batch], endTimeArray[batch], restrictionTypeArray[batch]); let receipt = await common.sendTransaction(action); - console.log(chalk.green('Add multiple restrictions transaction was successful.')); + console.log(chalk.green('Add multiple custom restrictions transaction was successful.')); console.log(`${receipt.gasUsed} gas used.Spent: ${web3.utils.fromWei((new web3.utils.BN(receipt.gasUsed)).mul(new web3.utils.BN(defaultGasPrice)))} ETH`); } } -async function modifyRestrictionsInBatch() { - let csvFilePath = readlineSync.question(`Enter the path for csv data file (${MODIFY_RESTRICTIONS_DATA_CSV}): `, { - defaultInput: MODIFY_RESTRICTIONS_DATA_CSV +async function modifyCustomRestrictionsInBatch() { + let csvFilePath = readlineSync.question(`Enter the path for csv data file (${MODIFY_CUSTOM_RESTRICTIONS_DATA_CSV}): `, { + defaultInput: MODIFY_CUSTOM_RESTRICTIONS_DATA_CSV }); let batchSize = readlineSync.question(`Enter the max number of records per transaction or batch size (${gbl.constants.DEFAULT_BATCH_SIZE}): `, { limit: function (input) { @@ -2076,19 +2138,19 @@ async function modifyRestrictionsInBatch() { let batches = common.splitIntoBatches(validData, batchSize); let [holderArray, allowanceArray, startTimeArray, rollingPeriodArray, endTimeArray, restrictionTypeArray] = common.transposeBatches(batches); for (let batch = 0; batch < batches.length; batch++) { - console.log(`Batch ${batch + 1} - Attempting to modify restrictions to the following accounts: \n\n`, holderArray[batch], '\n'); + console.log(`Batch ${batch + 1} - Attempting to modify custom restrictions to the following accounts: \n\n`, holderArray[batch], '\n'); allowanceArray[batch] = allowanceArray[batch].map(n => web3.utils.toWei(n.toString())); restrictionTypeArray[batch] = restrictionTypeArray[batch].map(n => RESTRICTION_TYPES.indexOf(n)); let action = currentTransferManager.methods.modifyIndividualRestrictionMulti(holderArray[batch], allowanceArray[batch], startTimeArray[batch], rollingPeriodArray[batch], endTimeArray[batch], restrictionTypeArray[batch]); let receipt = await common.sendTransaction(action); - console.log(chalk.green('Modify multiple restrictions transaction was successful.')); + console.log(chalk.green('Modify multiple custom restrictions transaction was successful.')); console.log(`${receipt.gasUsed} gas used.Spent: ${web3.utils.fromWei((new web3.utils.BN(receipt.gasUsed)).mul(new web3.utils.BN(defaultGasPrice)))} ETH`); } } -async function removeRestrictionsInBatch() { - let csvFilePath = readlineSync.question(`Enter the path for csv data file (${REMOVE_RESTRICTIONS_DATA_CSV}): `, { - defaultInput: REMOVE_RESTRICTIONS_DATA_CSV +async function removeCustomRestrictionsInBatch() { + let csvFilePath = readlineSync.question(`Enter the path for csv data file (${REMOVE_CUSTOM_RESTRICTIONS_DATA_CSV}): `, { + defaultInput: REMOVE_CUSTOM_RESTRICTIONS_DATA_CSV }); let batchSize = readlineSync.question(`Enter the max number of records per transaction or batch size (${gbl.constants.DEFAULT_BATCH_SIZE}): `, { limit: function (input) { @@ -2106,10 +2168,10 @@ async function removeRestrictionsInBatch() { let batches = common.splitIntoBatches(validData, batchSize); let [holderArray] = common.transposeBatches(batches); for (let batch = 0; batch < batches.length; batch++) { - console.log(`Batch ${batch + 1} - Attempting to remove restrictions to the following accounts: \n\n`, holderArray[batch], '\n'); + console.log(`Batch ${batch + 1} - Attempting to remove custom restrictions to the following accounts: \n\n`, holderArray[batch], '\n'); let action = currentTransferManager.methods.removeIndividualRestrictionMulti(holderArray[batch]); let receipt = await common.sendTransaction(action); - console.log(chalk.green('Remove multiple restrictions transaction was successful.')); + console.log(chalk.green('Remove multiple custom restrictions transaction was successful.')); console.log(`${receipt.gasUsed} gas used.Spent: ${web3.utils.fromWei((new web3.utils.BN(receipt.gasUsed)).mul(new web3.utils.BN(defaultGasPrice)))} ETH`); } } @@ -2118,9 +2180,9 @@ function inputRestrictionData(isDaily) { let restriction = {}; restriction.restrictionType = readlineSync.keyInSelect(RESTRICTION_TYPES, 'How do you want to set the allowance? ', { cancel: false }); if (restriction.restrictionType == RESTRICTION_TYPES.indexOf('Fixed')) { - restriction.allowedTokens = web3.utils.toWei(readlineSync.questionInt(`Enter the maximum amount of tokens allowed to be traded every ${isDaily ? 'day' : 'rolling period'}: `).toString()); + restriction.allowedTokens = web3.utils.toWei(readlineSync.question(`Enter the maximum amount of tokens allowed to be traded every ${isDaily ? 'day' : 'rolling period'}: `).toString()); } else { - restriction.allowedTokens = toWeiPercentage(readlineSync.questionInt(`Enter the maximum percentage of total supply allowed to be traded every ${isDaily ? 'day' : 'rolling period'}: `).toString()); + restriction.allowedTokens = toWeiPercentage(readlineSync.question(`Enter the maximum percentage of total supply allowed to be traded every ${isDaily ? 'day' : 'rolling period'}: `).toString()); } if (isDaily) { restriction.rollingPeriodInDays = 1; @@ -2129,7 +2191,7 @@ function inputRestrictionData(isDaily) { } restriction.startTime = readlineSync.questionInt(`Enter the time (Unix Epoch time) at which restriction get into effect (now = 0): `, { defaultInput: 0 }); let oneMonthFromNow = Math.floor(Date.now() / 1000) + gbl.constants.DURATION.days(30); - restriction.endTime = readlineSync.question(`Enter the time (Unix Epoch time) when the purchase lockup period ends and the investor can freely purchase tokens from others (1 week from now = ${oneMonthFromNow}): `, { + restriction.endTime = readlineSync.question(`Enter the time (Unix Epoch time) when the purchase lockup period ends and the investor can freely purchase tokens from others (1 month from now = ${oneMonthFromNow}): `, { limit: function (input) { return input > restriction.startTime + gbl.constants.DURATION.days(restriction.rollingPeriodInDays); }, @@ -2551,11 +2613,11 @@ function signData(tmAddress, investorAddress, fromTime, toTime, expiryTime, rest */ function toWeiPercentage(number) { - return new web3.utils.BN(web3.utils.toWei(number)).divn(100); + return web3.utils.toWei((parseFloat(number) / 100).toString()); } function fromWeiPercentage(number) { - return web3.utils.fromWei(new web3.utils.BN(number).muln(100)); + return web3.utils.fromWei(new web3.utils.BN(number).muln(100)).toString(); } async function getAllModulesByType(type) { diff --git a/CLI/data/Transfer/VRTM/add_custom_restriction_data.csv b/CLI/data/Transfer/VRTM/add_custom_restriction_data.csv new file mode 100644 index 000000000..1807e90e6 --- /dev/null +++ b/CLI/data/Transfer/VRTM/add_custom_restriction_data.csv @@ -0,0 +1,8 @@ +0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,1000,8/1/2019,90,10/10/2019,"Fixed" +0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,8/2/2019,30,10/12/2019,"Fixed" +0xac297053173b02b02a737d47f7b4a718e5b170ef,500,8/1/2019,15,10/1/2019,"Fixed" +0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,8/5/2019,90,10/10/2019,"Percentage" +0x10223927009b8add0960359dd90d1449415b7ca9,0.25,8/3/2019,30,10/15/2019,"Percentage" +0x3c65cfe3de848cf38e9d76e9c3e57a2f1140b399,0.1,8/10/2019,15,10/10/2019,"Percentage" +0xabf60de3265b3017db7a1be66fc8b364ec1dbb98,1234,8/20/2019,10,10/22/2019,"Fixed" +0xb841fe5a89da1bbef2d0805fbd7ffcbbb2fca5e3,5678,8/1/2019,2,10/10/2019,"Fixed" \ No newline at end of file diff --git a/CLI/data/Transfer/VRTM/add_daily_restriction_data.csv b/CLI/data/Transfer/VRTM/add_daily_restriction_data.csv index 782c1107d..1486579b7 100644 --- a/CLI/data/Transfer/VRTM/add_daily_restriction_data.csv +++ b/CLI/data/Transfer/VRTM/add_daily_restriction_data.csv @@ -1,8 +1,8 @@ -0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,1000,1/8/2019,10/10/2019,"Fixed" -0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,1/8/2019,10/10/2019,"Fixed" -0xac297053173b02b02a737d47f7b4a718e5b170ef,500,1/8/2019,10/10/2019,"Fixed" -0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,1/8/2019,10/10/2019,"Percentage" -0x10223927009b8add0960359dd90d1449415b7ca9,0.25,1/8/2019,10/10/2019,"Percentage" -0x3c65cfe3de848cf38e9d76e9c3e57a2f1140b399,0.1,1/8/2019,10/10/2019,"Percentage" -0xabf60de3265b3017db7a1be66fc8b364ec1dbb98,1234,1/8/2019,10/10/2019,"Fixed" -0xb841fe5a89da1bbef2d0805fbd7ffcbbb2fca5e3,5678,1/8/2019,10/10/2019,"Fixed" \ No newline at end of file +0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,1000,8/1/2019,10/10/2019,"Fixed" +0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,8/2/2019,10/12/2019,"Fixed" +0xac297053173b02b02a737d47f7b4a718e5b170ef,500,8/1/2019,10/10/2019,"Fixed" +0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,8/3/2019,10/1/2019,"Percentage" +0x10223927009b8add0960359dd90d1449415b7ca9,0.25,8/1/2019,10/10/2019,"Percentage" +0x3c65cfe3de848cf38e9d76e9c3e57a2f1140b399,0.1,8/1/2019,10/5/2019,"Percentage" +0xabf60de3265b3017db7a1be66fc8b364ec1dbb98,1234,8/12/2019,10/10/2019,"Fixed" +0xb841fe5a89da1bbef2d0805fbd7ffcbbb2fca5e3,5678,8/1/2019,10/10/2019,"Fixed" \ No newline at end of file diff --git a/CLI/data/Transfer/VRTM/add_restriction_data.csv b/CLI/data/Transfer/VRTM/add_restriction_data.csv deleted file mode 100644 index 072151a64..000000000 --- a/CLI/data/Transfer/VRTM/add_restriction_data.csv +++ /dev/null @@ -1,8 +0,0 @@ -0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,1000,1/8/2019,90,10/10/2019,"Fixed" -0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,1/8/2019,30,10/10/2019,"Fixed" -0xac297053173b02b02a737d47f7b4a718e5b170ef,500,1/8/2019,15,10/10/2019,"Fixed" -0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,1/8/2019,90,10/10/2019,"Percentage" -0x10223927009b8add0960359dd90d1449415b7ca9,0.25,1/8/2019,30,10/10/2019,"Percentage" -0x3c65cfe3de848cf38e9d76e9c3e57a2f1140b399,0.1,1/8/2019,15,10/10/2019,"Percentage" -0xabf60de3265b3017db7a1be66fc8b364ec1dbb98,1234,1/8/2019,10,10/10/2019,"Fixed" -0xb841fe5a89da1bbef2d0805fbd7ffcbbb2fca5e3,5678,1/8/2019,2,10/10/2019,"Fixed" \ No newline at end of file diff --git a/CLI/data/Transfer/VRTM/modify_custom_restriction_data.csv b/CLI/data/Transfer/VRTM/modify_custom_restriction_data.csv new file mode 100644 index 000000000..b69f43361 --- /dev/null +++ b/CLI/data/Transfer/VRTM/modify_custom_restriction_data.csv @@ -0,0 +1,5 @@ +0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,2000,8/1/2019,90,10/10/2019,"Fixed" +0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,8/2/2019,30,10/10/2019,"Fixed" +0xac297053173b02b02a737d47f7b4a718e5b170ef,500,8/1/2019,20,10/10/2019,"Fixed" +0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,8/1/2019,90,20/10/2019,"Percentage" +0x10223927009b8add0960359dd90d1449415b7ca9,25,8/1/2019,30,10/10/2019,"Fixed" \ No newline at end of file diff --git a/CLI/data/Transfer/VRTM/modify_daily_restriction_data.csv b/CLI/data/Transfer/VRTM/modify_daily_restriction_data.csv index 194e9b1d5..908c164e9 100644 --- a/CLI/data/Transfer/VRTM/modify_daily_restriction_data.csv +++ b/CLI/data/Transfer/VRTM/modify_daily_restriction_data.csv @@ -1,5 +1,5 @@ -0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,2000,1/8/2019,10/10/2019,"Fixed" -0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,2/8/2019,10/10/2019,"Fixed" -0xac297053173b02b02a737d47f7b4a718e5b170ef,500,1/8/2019,10/10/2019,"Fixed" -0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,1/8/2019,20/10/2019,"Percentage" -0x10223927009b8add0960359dd90d1449415b7ca9,25,1/8/2019,10/10/2019,"Fixed" +0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,2000,8/1/2019,10/10/2019,"Fixed" +0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,8/1/2019,10/10/2019,"Fixed" +0xac297053173b02b02a737d47f7b4a718e5b170ef,500,8/1/2019,10/10/2019,"Fixed" +0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,8/1/2019,20/10/2019,"Percentage" +0x10223927009b8add0960359dd90d1449415b7ca9,25,8/1/2019,10/10/2019,"Fixed" diff --git a/CLI/data/Transfer/VRTM/modify_restriction_data.csv b/CLI/data/Transfer/VRTM/modify_restriction_data.csv deleted file mode 100644 index 588e39211..000000000 --- a/CLI/data/Transfer/VRTM/modify_restriction_data.csv +++ /dev/null @@ -1,5 +0,0 @@ -0xee7ae74d964f2be7d72c1b187b38e2ed3615d4d1,2000,1/8/2019,90,10/10/2019,"Fixed" -0x2f0fd672bf222413cc69dc1f4f1d7e93ad1763a1,2000,2/8/2019,30,10/10/2019,"Fixed" -0xac297053173b02b02a737d47f7b4a718e5b170ef,500,1/8/2019,20,10/10/2019,"Fixed" -0x49fc0b78238dab644698a90fa351b4c749e123d2,0.15,1/8/2019,90,20/10/2019,"Percentage" -0x10223927009b8add0960359dd90d1449415b7ca9,25,1/8/2019,30,10/10/2019,"Fixed" \ No newline at end of file diff --git a/CLI/data/Transfer/VRTM/remove_restriction_data.csv b/CLI/data/Transfer/VRTM/remove_custom_restriction_data.csv similarity index 100% rename from CLI/data/Transfer/VRTM/remove_restriction_data.csv rename to CLI/data/Transfer/VRTM/remove_custom_restriction_data.csv diff --git a/contracts/libraries/VolumeRestrictionLib.sol b/contracts/libraries/VolumeRestrictionLib.sol new file mode 100644 index 000000000..e1e94a50b --- /dev/null +++ b/contracts/libraries/VolumeRestrictionLib.sol @@ -0,0 +1,87 @@ +pragma solidity ^0.4.24; + +import "./BokkyPooBahsDateTimeLibrary.sol"; +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "../interfaces/ISecurityToken.sol"; + +library VolumeRestrictionLib { + + using SafeMath for uint256; + + enum TypeOfPeriod { MultipleDays, OneDay, Both } + + struct RestrictedHolder { + // 1 represent true & 0 for false + uint8 seen; + // Type of period will be enum index of TypeOfPeriod enum + uint8 typeOfPeriod; + // Index of the array where the holder address lives + uint128 index; + } + + struct RestrictedData { + mapping(address => RestrictedHolder) restrictedHolders; + address[] restrictedAddresses; + } + + function _checkLengthOfArray( + address[] _holders, + uint256[] _allowedTokens, + uint256[] _startTimes, + uint256[] _rollingPeriodInDays, + uint256[] _endTimes, + uint256[] _restrictionTypes + ) + internal + pure + { + require( + _holders.length == _allowedTokens.length && + _allowedTokens.length == _startTimes.length && + _startTimes.length == _rollingPeriodInDays.length && + _rollingPeriodInDays.length == _endTimes.length && + _endTimes.length == _restrictionTypes.length, + "Length mismatch" + ); + } + + function _deleteHolderFromList(RestrictedData storage data, address _holder, uint8 _typeOfPeriod) public { + // Deleting the holder if holder's type of Period is `Both` type otherwise + // it will assign the given type `_typeOfPeriod` to the _holder typeOfPeriod + // `_typeOfPeriod` it always be contrary to the removing restriction + // if removing restriction is individual then typeOfPeriod is TypeOfPeriod.OneDay + // in uint8 its value is 1. if removing restriction is daily individual then typeOfPeriod + // is TypeOfPeriod.MultipleDays in uint8 its value is 0. + if (data.restrictedHolders[_holder].typeOfPeriod != uint8(TypeOfPeriod.Both)) { + uint128 index = data.restrictedHolders[_holder].index; + uint256 _len = data.restrictedAddresses.length; + if (index != _len) { + data.restrictedHolders[data.restrictedAddresses[_len - 1]].index = index; + data.restrictedAddresses[index - 1] = data.restrictedAddresses[_len - 1]; + } + delete data.restrictedHolders[_holder]; + data.restrictedAddresses.length--; + } else { + data.restrictedHolders[_holder].typeOfPeriod = _typeOfPeriod; + } + } + + function _addRestrictionData(RestrictedData storage data, address _holder, uint8 _callFrom, uint256 _endTime) public { + uint128 index = data.restrictedHolders[_holder].index; + if (data.restrictedHolders[_holder].seen == 0) { + data.restrictedAddresses.push(_holder); + index = uint128(data.restrictedAddresses.length); + } + uint8 _type = _getTypeOfPeriod(data.restrictedHolders[_holder].typeOfPeriod, _callFrom, _endTime); + data.restrictedHolders[_holder] = RestrictedHolder(uint8(1), _type, index); + } + + function _getTypeOfPeriod(uint8 _currentTypeOfPeriod, uint8 _callFrom, uint256 _endTime) internal pure returns(uint8) { + if (_currentTypeOfPeriod != _callFrom && _endTime != uint256(0)) + return uint8(TypeOfPeriod.Both); + else + return _callFrom; + } + + +} \ No newline at end of file diff --git a/contracts/modules/TransferManager/VolumeRestrictionTM.sol b/contracts/modules/TransferManager/VolumeRestrictionTM.sol index 44534351d..5cf1e4ac6 100644 --- a/contracts/modules/TransferManager/VolumeRestrictionTM.sol +++ b/contracts/modules/TransferManager/VolumeRestrictionTM.sol @@ -6,7 +6,7 @@ import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../../libraries/BokkyPooBahsDateTimeLibrary.sol"; contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { - + using SafeMath for uint256; // permission definition @@ -112,32 +112,41 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { */ function verifyTransfer(address _from, address /*_to */, uint256 _amount, bytes /*_data*/, bool _isTransfer) public returns (Result) { // If `_from` is present in the exemptionList or it is `0x0` address then it will not follow the vol restriction - if (!paused && _from != address(0) && !exemptList[_from]) { + if (!paused && _from != address(0) && exemptIndex[_from] == 0) { // Function must only be called by the associated security token if _isTransfer == true require(msg.sender == securityToken || !_isTransfer); - // Checking the individual restriction if the `_from` comes in the individual category - if ((individualRestriction[_from].endTime >= now && individualRestriction[_from].startTime <= now) + // Checking the individual restriction if the `_from` comes in the individual category + if ((individualRestriction[_from].endTime >= now && individualRestriction[_from].startTime <= now) || (individualDailyRestriction[_from].endTime >= now && individualDailyRestriction[_from].startTime <= now)) { return _individualRestrictionCheck(_from, _amount, _isTransfer); // If the `_from` doesn't fall under the individual category. It will processed with in the global category automatically } else if ((defaultRestriction.endTime >= now && defaultRestriction.startTime <= now) || (defaultDailyRestriction.endTime >= now && defaultDailyRestriction.startTime <= now)) { - + return _defaultRestrictionCheck(_from, _amount, _isTransfer); } - } + } return Result.NA; } /** * @notice Add/Remove wallet address from the exempt list * @param _wallet Ethereum wallet/contract address that need to be exempted - * @param _change Boolean value used to add (i.e true) or remove (i.e false) from the list + * @param _change Boolean value used to add (i.e true) or remove (i.e false) from the list */ function changeExemptWalletList(address _wallet, bool _change) public withPerm(ADMIN) { - require(_wallet != address(0), "Invalid address"); - exemptList[_wallet] = _change; + require(_wallet != address(0)); + require((exemptIndex[_wallet] == 0) == _change); + if (_change) { + exemptAddresses.push(_wallet); + exemptIndex[_wallet] = exemptAddresses.length; + } else { + exemptAddresses[exemptIndex[_wallet] - 1] = exemptAddresses[exemptAddresses.length - 1]; + exemptIndex[exemptAddresses[exemptIndex[_wallet] - 1]] = exemptIndex[_wallet]; + delete exemptIndex[_wallet]; + exemptAddresses.length --; + } emit ChangedExemptWalletList(_wallet, _change); } @@ -156,7 +165,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _startTime, uint256 _rollingPeriodInDays, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) external withPerm(ADMIN) @@ -178,37 +187,36 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _startTime, uint256 _rollingPeriodInDays, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) internal - { - - uint256 startTime = _startTime; + { + if (_startTime == 0) { - startTime = now; + _startTime = now; } require( individualRestriction[_holder].endTime < now, - "Already present" + "Not Allowed" ); - require(_holder != address(0) && !exemptList[_holder], "Invalid address"); - require(startTime >= now, "Invalid startTime"); - _checkInputParams(_allowedTokens, startTime, _rollingPeriodInDays, _endTime, _restrictionType); - + require(_holder != address(0) && exemptIndex[_holder] == 0, "Invalid address"); + _checkInputParams(_allowedTokens, _startTime, _rollingPeriodInDays, _endTime, _restrictionType, now); + if (individualRestriction[_holder].endTime != 0) { _removeIndividualRestriction(_holder); } individualRestriction[_holder] = VolumeRestriction( _allowedTokens, - startTime, + _startTime, _rollingPeriodInDays, _endTime, RestrictionType(_restrictionType) ); + VolumeRestrictionLib._addRestrictionData(holderData, _holder, uint8(TypeOfPeriod.MultipleDays), individualRestriction[_holder].endTime); emit AddIndividualRestriction( _holder, _allowedTokens, - startTime, + _startTime, _rollingPeriodInDays, _endTime, _restrictionType @@ -228,11 +236,11 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _allowedTokens, uint256 _startTime, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) external withPerm(ADMIN) - { + { _addIndividualDailyRestriction( _holder, _allowedTokens, @@ -248,32 +256,30 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _allowedTokens, uint256 _startTime, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) internal - { - - uint256 startTime = _startTime; + { if (_startTime == 0) { - startTime = now; + _startTime = now; } require( individualDailyRestriction[_holder].endTime < now, "Not Allowed" ); - require(startTime >= now, "Invalid startTime"); - _checkInputParams(_allowedTokens, startTime, 1, _endTime, _restrictionType); + _checkInputParams(_allowedTokens, _startTime, 1, _endTime, _restrictionType, now); individualDailyRestriction[_holder] = VolumeRestriction( _allowedTokens, - startTime, + _startTime, 1, _endTime, RestrictionType(_restrictionType) ); + VolumeRestrictionLib._addRestrictionData(holderData, _holder, uint8(TypeOfPeriod.OneDay), individualRestriction[_holder].endTime); emit AddIndividualDailyRestriction( _holder, _allowedTokens, - startTime, + _startTime, 1, _endTime, _restrictionType @@ -293,25 +299,20 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256[] _allowedTokens, uint256[] _startTimes, uint256[] _endTimes, - uint256[] _restrictionTypes + uint256[] _restrictionTypes ) public withPerm(ADMIN) { - require( - _allowedTokens.length == _startTimes.length && - _startTimes.length == _holders.length && - _holders.length == _endTimes.length && - _endTimes.length == _restrictionTypes.length, - "Array length mismatch" - ); + //NB - we duplicate _startTimes below to allow function reuse + VolumeRestrictionLib._checkLengthOfArray(_holders, _allowedTokens, _startTimes, _startTimes, _endTimes, _restrictionTypes); for (uint256 i = 0; i < _holders.length; i++) { _addIndividualDailyRestriction( _holders[i], _allowedTokens[i], _startTimes[i], _endTimes[i], - _restrictionTypes[i] + _restrictionTypes[i] ); } } @@ -331,13 +332,12 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256[] _startTimes, uint256[] _rollingPeriodInDays, uint256[] _endTimes, - uint256[] _restrictionTypes + uint256[] _restrictionTypes ) public withPerm(ADMIN) { - _checkLengthOfArray(_allowedTokens, _startTimes, _rollingPeriodInDays, _endTimes, _restrictionTypes); - require(_holders.length == _allowedTokens.length, "Length mismatch"); + VolumeRestrictionLib._checkLengthOfArray(_holders, _allowedTokens, _startTimes, _rollingPeriodInDays, _endTimes, _restrictionTypes); for (uint256 i = 0; i < _holders.length; i++) { _addIndividualRestriction( _holders[i], @@ -345,7 +345,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { _startTimes[i], _rollingPeriodInDays[i], _endTimes[i], - _restrictionTypes[i] + _restrictionTypes[i] ); } } @@ -363,21 +363,20 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _startTime, uint256 _rollingPeriodInDays, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) external withPerm(ADMIN) - { + { uint256 startTime = _startTime; if (_startTime == 0) { startTime = now; } require( defaultRestriction.endTime < now, - "Not allowed" + "Not Allowed" ); - require(startTime >= now, "Invalid startTime"); - _checkInputParams(_allowedTokens, startTime, _rollingPeriodInDays, _endTime, _restrictionType); + _checkInputParams(_allowedTokens, startTime, _rollingPeriodInDays, _endTime, _restrictionType, now); defaultRestriction = VolumeRestriction( _allowedTokens, startTime, @@ -405,11 +404,11 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _allowedTokens, uint256 _startTime, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) external withPerm(ADMIN) - { + { uint256 startTime = _startTime; if (_startTime == 0) { startTime = now; @@ -418,8 +417,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { defaultDailyRestriction.endTime < now, "Not Allowed" ); - require(startTime >= now, "Invalid startTime"); - _checkInputParams(_allowedTokens, startTime, 1, _endTime, _restrictionType); + _checkInputParams(_allowedTokens, startTime, 1, _endTime, _restrictionType, now); defaultDailyRestriction = VolumeRestriction( _allowedTokens, startTime, @@ -438,7 +436,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { /** * @notice use to remove the individual restriction for a given address - * @param _holder Address of the user + * @param _holder Address of the user */ function removeIndividualRestriction(address _holder) external withPerm(ADMIN) { _removeIndividualRestriction(_holder); @@ -446,9 +444,10 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { /// @notice Internal function to facilitate the removal of individual restriction function _removeIndividualRestriction(address _holder) internal { - require(_holder != address(0), "Invalid address"); - require(individualRestriction[_holder].endTime != 0, "Not present"); + require(_holder != address(0)); + require(individualRestriction[_holder].endTime != 0); individualRestriction[_holder] = VolumeRestriction(0, 0, 0, 0, RestrictionType(0)); + VolumeRestrictionLib._deleteHolderFromList(holderData, _holder, uint8(TypeOfPeriod.OneDay)); userToBucket[_holder].lastTradedDayTime = 0; userToBucket[_holder].sumOfLastPeriod = 0; userToBucket[_holder].daysCovered = 0; @@ -457,7 +456,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { /** * @notice use to remove the individual restriction for a given address - * @param _holders Array of address of the user + * @param _holders Array of address of the user */ function removeIndividualRestrictionMulti(address[] _holders) external withPerm(ADMIN) { for (uint256 i = 0; i < _holders.length; i++) { @@ -467,7 +466,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { /** * @notice use to remove the individual daily restriction for a given address - * @param _holder Address of the user + * @param _holder Address of the user */ function removeIndividualDailyRestriction(address _holder) external withPerm(ADMIN) { _removeIndividualDailyRestriction(_holder); @@ -475,16 +474,17 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { /// @notice Internal function to facilitate the removal of individual daily restriction function _removeIndividualDailyRestriction(address _holder) internal { - require(_holder != address(0), "Invalid address"); - require(individualDailyRestriction[_holder].endTime != 0, "Not present"); + require(_holder != address(0)); + require(individualDailyRestriction[_holder].endTime != 0); individualDailyRestriction[_holder] = VolumeRestriction(0, 0, 0, 0, RestrictionType(0)); + VolumeRestrictionLib._deleteHolderFromList(holderData, _holder, uint8(TypeOfPeriod.MultipleDays)); userToBucket[_holder].dailyLastTradedDayTime = 0; emit IndividualDailyRestrictionRemoved(_holder); } /** * @notice use to remove the individual daily restriction for a given address - * @param _holders Array of address of the user + * @param _holders Array of address of the user */ function removeIndividualDailyRestrictionMulti(address[] _holders) external withPerm(ADMIN) { for (uint256 i = 0; i < _holders.length; i++) { @@ -508,7 +508,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { require(defaultDailyRestriction.endTime != 0); defaultDailyRestriction = VolumeRestriction(0, 0, 0, 0, RestrictionType(0)); emit DefaultDailyRestrictionRemoved(); - } + } /** * @notice Use to modify the existing individual restriction for a given token holder @@ -525,7 +525,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _startTime, uint256 _rollingPeriodInDays, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) external withPerm(ADMIN) @@ -547,20 +547,19 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _startTime, uint256 _rollingPeriodInDays, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) internal - { - uint256 startTime = _startTime; + { + /* uint256 startTime = _startTime; */ if (_startTime == 0) { - startTime = now; + _startTime = now; } - require(individualRestriction[_holder].startTime > now, "Not allowed"); - require(startTime >= now, "Invalid startTime"); - _checkInputParams(_allowedTokens, startTime, _rollingPeriodInDays, _endTime, _restrictionType); + require(individualRestriction[_holder].startTime > now, "Not Allowed"); + _checkInputParams(_allowedTokens, _startTime, _rollingPeriodInDays, _endTime, _restrictionType, now); individualRestriction[_holder] = VolumeRestriction( _allowedTokens, - startTime, + _startTime, _rollingPeriodInDays, _endTime, RestrictionType(_restrictionType) @@ -568,7 +567,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { emit ModifyIndividualRestriction( _holder, _allowedTokens, - startTime, + _startTime, _rollingPeriodInDays, _endTime, _restrictionType @@ -590,7 +589,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _allowedTokens, uint256 _startTime, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) external withPerm(ADMIN) @@ -610,24 +609,19 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _allowedTokens, uint256 _startTime, uint256 _endTime, - uint256 _restrictionType + uint256 _restrictionType ) internal - { - uint256 startTime = _startTime; + { if (_startTime == 0) { - startTime = now; + _startTime = now; } - _checkInputParams(_allowedTokens, startTime, 1, _endTime, _restrictionType); - // If old startTime is already passed then new startTime should be greater than or equal to the - // old startTime otherwise any past startTime can be allowed in compare to earlier startTime. - if (individualDailyRestriction[_holder].startTime <= now) - require(startTime >= individualDailyRestriction[_holder].startTime, "Invalid StartTime"); - else - require(startTime >= now); + _checkInputParams(_allowedTokens, _startTime, 1, _endTime, _restrictionType, + (individualDailyRestriction[_holder].startTime <= now ? individualDailyRestriction[_holder].startTime : now) + ); individualDailyRestriction[_holder] = VolumeRestriction( _allowedTokens, - startTime, + _startTime, 1, _endTime, RestrictionType(_restrictionType) @@ -635,7 +629,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { emit ModifyIndividualDailyRestriction( _holder, _allowedTokens, - startTime, + _startTime, 1, _endTime, _restrictionType @@ -655,29 +649,23 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256[] _allowedTokens, uint256[] _startTimes, uint256[] _endTimes, - uint256[] _restrictionTypes + uint256[] _restrictionTypes ) public withPerm(ADMIN) { - require( - _allowedTokens.length == _startTimes.length && - _startTimes.length == _holders.length && - _holders.length == _endTimes.length && - _endTimes.length == _restrictionTypes.length, - "Array length mismatch" - ); - require(_holders.length == _allowedTokens.length, "Length mismatch"); + //NB - we duplicate _startTimes below to allow function reuse + VolumeRestrictionLib._checkLengthOfArray(_holders, _allowedTokens, _startTimes, _startTimes, _endTimes, _restrictionTypes); for (uint256 i = 0; i < _holders.length; i++) { _modifyIndividualDailyRestriction( _holders[i], _allowedTokens[i], _startTimes[i], _endTimes[i], - _restrictionTypes[i] + _restrictionTypes[i] ); } - } + } /** * @notice Use to modify the existing individual restriction for multiple token holders @@ -694,13 +682,12 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256[] _startTimes, uint256[] _rollingPeriodInDays, uint256[] _endTimes, - uint256[] _restrictionTypes + uint256[] _restrictionTypes ) public withPerm(ADMIN) { - _checkLengthOfArray(_allowedTokens, _startTimes, _rollingPeriodInDays, _endTimes, _restrictionTypes); - require(_holders.length == _allowedTokens.length, "Length mismatch"); + VolumeRestrictionLib._checkLengthOfArray(_holders, _allowedTokens, _startTimes, _rollingPeriodInDays, _endTimes, _restrictionTypes); for (uint256 i = 0; i < _holders.length; i++) { _modifyIndividualRestriction( _holders[i], @@ -708,10 +695,10 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { _startTimes[i], _rollingPeriodInDays[i], _endTimes[i], - _restrictionTypes[i] + _restrictionTypes[i] ); } - } + } /** * @notice Use to modify the global restriction for all token holder @@ -730,14 +717,13 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { ) external withPerm(ADMIN) - { - require(defaultRestriction.startTime > now, "Not allowed"); + { + require(defaultRestriction.startTime > now, "Not Allowed"); uint256 startTime = _startTime; if (_startTime == 0) { startTime = now; } - require(startTime >= now, "Invalid startTime"); - _checkInputParams(_allowedTokens, startTime, _rollingPeriodInDays, _endTime, _restrictionType); + _checkInputParams(_allowedTokens, startTime, _rollingPeriodInDays, _endTime, _restrictionType, now); defaultRestriction = VolumeRestriction( _allowedTokens, startTime, @@ -771,18 +757,16 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { ) external withPerm(ADMIN) - { + { uint256 startTime = _startTime; if (_startTime == 0) { startTime = now; } - _checkInputParams(_allowedTokens, startTime, 1, _endTime, _restrictionType); - // If old startTime is already passed then new startTime should be greater than or equal to the + // If old startTime is already passed then new startTime should be greater than or equal to the // old startTime otherwise any past startTime can be allowed in compare to earlier startTime. - if (defaultDailyRestriction.startTime <= now) - require(startTime >= defaultDailyRestriction.startTime, "Invalid StartTime"); - else - require(startTime >= now); + _checkInputParams(_allowedTokens, startTime, 1, _endTime, _restrictionType, + (defaultDailyRestriction.startTime <= now ? defaultDailyRestriction.startTime : now) + ); defaultDailyRestriction = VolumeRestriction( _allowedTokens, startTime, @@ -803,9 +787,9 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { * @notice Internal function used to validate the transaction for a given address * If it validates then it also update the storage corressponds to the default restriction */ - function _defaultRestrictionCheck(address _from, uint256 _amount, bool _isTransfer) internal returns (Result) { + function _defaultRestrictionCheck(address _from, uint256 _amount, bool _isTransfer) internal returns (Result) { // using the variable to avoid stack too deep error - BucketDetails memory bucketDetails = defaultUserToBucket[_from]; + BucketDetails storage bucketDetails = defaultUserToBucket[_from]; uint256 daysCovered = defaultRestriction.rollingPeriodInDays; uint256 fromTimestamp = 0; uint256 sumOfLastPeriod = 0; @@ -820,7 +804,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { // Picking up the last timestamp fromTimestamp = bucketDetails.lastTradedDayTime; } - + // Check with the bucket and parse all the new timestamps to calculate the sumOfLastPeriod // re-using the local variables to avoid the stack too deep error. (sumOfLastPeriod, fromTimestamp, daysCovered) = _bucketCheck( @@ -836,7 +820,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { } } (allowedDaily, dailyTime) = _dailyTxCheck(_from, _amount, bucketDetails.dailyLastTradedDayTime, defaultDailyRestriction); - + if (_isTransfer) { _updateStorage( _from, @@ -856,7 +840,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { * @notice Internal function used to validate the transaction for a given address * If it validates then it also update the storage corressponds to the individual restriction */ - function _individualRestrictionCheck(address _from, uint256 _amount, bool _isTransfer) internal returns (Result) { + function _individualRestrictionCheck(address _from, uint256 _amount, bool _isTransfer) internal returns (Result) { // using the variable to avoid stack too deep error BucketDetails memory bucketDetails = userToBucket[_from]; VolumeRestriction memory dailyRestriction = individualDailyRestriction[_from]; @@ -875,7 +859,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { // Picking up the last timestamp fromTimestamp = bucketDetails.lastTradedDayTime; } - + // Check with the bucket and parse all the new timestamps to calculate the sumOfLastPeriod // re-using the local variables to avoid the stack too deep error. (sumOfLastPeriod, fromTimestamp, daysCovered) = _bucketCheck( @@ -891,7 +875,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { } } (allowedDaily, dailyTime) = _dailyTxCheck(_from, _amount, bucketDetails.dailyLastTradedDayTime, dailyRestriction); - + if (_isTransfer) { _updateStorage( _from, @@ -913,14 +897,14 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 amount, uint256 dailyLastTradedDayTime, VolumeRestriction restriction - ) + ) internal view returns(bool, uint256) { // Checking whether the daily restriction is added or not if yes then calculate // the total amount get traded on a particular day (~ _fromTime) - if ( now <= restriction.endTime && now >= restriction.startTime) { + if ( now <= restriction.endTime && now >= restriction.startTime) { uint256 txSumOfDay = 0; if (dailyLastTradedDayTime == 0 || dailyLastTradedDayTime < restriction.startTime) // This if condition will be executed when the individual daily restriction executed first time @@ -962,7 +946,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { if (counter >= _rollingPeriodInDays) { // Subtracting the former value(Sum of all the txn amount of that day) from the sumOfLastPeriod // The below line subtracts (the traded volume on days no longer covered by rolling period) from sumOfLastPeriod. - // Every loop execution subtracts one day's trade volume. + // Every loop execution subtracts one day's trade volume. // Loop starts from the first day covered in sumOfLastPeriod upto the day that is covered by rolling period. uint256 temp = _bucketDetails.daysCovered.sub(counter.sub(_rollingPeriodInDays)); temp = _bucketDetails.lastTradedDayTime.sub(temp.mul(1 days)); @@ -974,7 +958,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { } } // calculating the timestamp that will used as an index of the next bucket - // i.e buckets period will be look like this T1 to T2-1, T2 to T3-1 .... + // i.e buckets period will be look like this T1 to T2-1, T2 to T3-1 .... // where T1,T2,T3 are timestamps having 24 hrs difference _fromTime = _fromTime.add(_diffDays.mul(1 days)); return (sumOfLastPeriod, _fromTime, counter); @@ -984,11 +968,11 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _sumOfLastPeriod, uint256 _amountToTransact, VolumeRestriction _restriction - ) + ) internal view returns (bool) - { + { uint256 _allowedAmount = 0; if (_restriction.typeOfRestriction == RestrictionType.Percentage) { _allowedAmount = (_restriction.allowedTokens.mul(ISecurityToken(securityToken).totalSupply())) / uint256(10) ** 18; @@ -1004,14 +988,14 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _amount, uint256 _lastTradedDayTime, uint256 _sumOfLastPeriod, - uint256 _daysCovered, + uint256 _daysCovered, uint256 _dailyLastTradedDayTime, uint256 _endTime, bool isDefault ) - internal - { - + internal + { + if (isDefault){ BucketDetails storage defaultUserToBucketDetails = defaultUserToBucket[_from]; _updateStorageActual(_from, _amount, _lastTradedDayTime, _sumOfLastPeriod, _daysCovered, _dailyLastTradedDayTime, _endTime, defaultUserToBucketDetails); @@ -1027,13 +1011,13 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { uint256 _amount, uint256 _lastTradedDayTime, uint256 _sumOfLastPeriod, - uint256 _daysCovered, + uint256 _daysCovered, uint256 _dailyLastTradedDayTime, uint256 _endTime, BucketDetails storage details ) - internal - { + internal + { // Cheap storage technique if (details.lastTradedDayTime != _lastTradedDayTime) { // Assigning the latest transaction timestamp of the day @@ -1056,50 +1040,35 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { // Increasing the total amount of the day by `_amount` bucket[_from][_dailyLastTradedDayTime] = bucket[_from][_dailyLastTradedDayTime].add(_amount); } - } + } } function _checkInputParams( uint256 _allowedTokens, - uint256 _startTime, - uint256 _rollingPeriodDays, + uint256 _startTime, + uint256 _rollingPeriodDays, uint256 _endTime, - uint256 _restrictionType - ) + uint256 _restrictionType, + uint256 _earliestStartTime + ) internal pure { require(_restrictionType == 0 || _restrictionType == 1, "Invalid type"); + require(_startTime >= _earliestStartTime, "Invalid startTime"); if (_restrictionType == uint256(RestrictionType.Fixed)) { require(_allowedTokens > 0, "Invalid value"); } else { require( _allowedTokens > 0 && _allowedTokens <= 100 * 10 ** 16, - "Percentage is not within (0,100]" + "Invalid value" ); } - require(_endTime > _startTime, "Invalid times"); // Maximum limit for the rollingPeriod is 365 days require(_rollingPeriodDays >= 1 && _rollingPeriodDays <= 365, "Invalid rollingperiod"); - require(BokkyPooBahsDateTimeLibrary.diffDays(_startTime, _endTime) >= _rollingPeriodDays, "Invalid start & end time"); - } - - function _checkLengthOfArray( - uint256[] _allowedTokens, - uint256[] _startTimes, - uint256[] _rollingPeriodInDays, - uint256[] _endTimes, - uint256[] _restrictionTypes - ) - internal - pure - { require( - _allowedTokens.length == _startTimes.length && - _startTimes.length == _rollingPeriodInDays.length && - _rollingPeriodInDays.length == _endTimes.length && - _endTimes.length == _restrictionTypes.length, - "Array length mismatch" + BokkyPooBahsDateTimeLibrary.diffDays(_startTime, _endTime) >= _rollingPeriodDays && _endTime > _startTime, + "Invalid times" ); } @@ -1111,7 +1080,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { * @return uint256 days covered * @return uint256 24h lastTradedDayTime */ - function getIndividualBucketDetailsToUser(address _user) external view returns(uint256, uint256, uint256, uint256) { + function getIndividualBucketDetailsToUser(address _user) public view returns(uint256, uint256, uint256, uint256) { return( userToBucket[_user].lastTradedDayTime, userToBucket[_user].sumOfLastPeriod, @@ -1128,7 +1097,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { * @return uint256 days covered * @return uint256 24h lastTradedDayTime */ - function getDefaultBucketDetailsToUser(address _user) external view returns(uint256, uint256, uint256, uint256) { + function getDefaultBucketDetailsToUser(address _user) public view returns(uint256, uint256, uint256, uint256) { return( defaultUserToBucket[_user].lastTradedDayTime, defaultUserToBucket[_user].sumOfLastPeriod, @@ -1140,7 +1109,7 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { /** * @notice Use to get the volume of token that being traded at a particular day (`_at` + 24 hours) for a given user * @param _user Address of the token holder - * @param _at Timestamp + * @param _at Timestamp */ function getTotalTradedByUser(address _user, uint256 _at) external view returns(uint256) { return bucket[_user][_at]; @@ -1153,6 +1122,80 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { return bytes4(0); } + /** + * @notice Use to return the list of exempted addresses + */ + function getExemptAddress() external view returns(address[]) { + return exemptAddresses; + } + + /** + * @notice Provide the restriction details of all the restricted addresses + * @return address List of the restricted addresses + * @return uint256 List of the tokens allowed to the restricted addresses corresponds to restricted address + * @return uint256 List of the start time of the restriction corresponds to restricted address + * @return uint256 List of the rolling period in days for a restriction corresponds to restricted address. + * @return uint256 List of the end time of the restriction corresponds to restricted address. + * @return uint8 List of the type of restriction to validate the value of the `allowedTokens` + * of the restriction corresponds to restricted address + */ + function getRestrictedData() external view returns( + address[] memory allAddresses, + uint256[] memory allowedTokens, + uint256[] memory startTime, + uint256[] memory rollingPeriodInDays, + uint256[] memory endTime, + uint8[] memory typeOfRestriction + ) { + uint256 counter = 0; + uint256 i = 0; + for (i = 0; i < holderData.restrictedAddresses.length; i++) { + counter = counter + (holderData.restrictedHolders[holderData.restrictedAddresses[i]].typeOfPeriod == uint8(2) ? 2 : 1); + } + allAddresses = new address[](counter); + allowedTokens = new uint256[](counter); + startTime = new uint256[](counter); + rollingPeriodInDays = new uint256[](counter); + endTime = new uint256[](counter); + typeOfRestriction = new uint8[](counter); + counter = 0; + for (i = 0; i < holderData.restrictedAddresses.length; i++) { + allAddresses[counter] = holderData.restrictedAddresses[i]; + if (holderData.restrictedHolders[holderData.restrictedAddresses[i]].typeOfPeriod == uint8(TypeOfPeriod.MultipleDays)) { + _setValues(individualRestriction[holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + else if (holderData.restrictedHolders[holderData.restrictedAddresses[i]].typeOfPeriod == uint8(TypeOfPeriod.OneDay)) { + _setValues(individualDailyRestriction[holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + else if (holderData.restrictedHolders[holderData.restrictedAddresses[i]].typeOfPeriod == uint8(TypeOfPeriod.Both)) { + _setValues(individualRestriction[holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + counter = counter + 1; + allAddresses[counter] = holderData.restrictedAddresses[i]; + _setValues(individualDailyRestriction[holderData.restrictedAddresses[i]], allowedTokens, startTime, rollingPeriodInDays, endTime, typeOfRestriction, counter); + } + counter ++; + } + } + + function _setValues( + VolumeRestriction memory restriction, + uint256[] memory allowedTokens, + uint256[] memory startTime, + uint256[] memory rollingPeriodInDays, + uint256[] memory endTime, + uint8[] memory typeOfRestriction, + uint256 index + ) + internal + pure + { + allowedTokens[index] = restriction.allowedTokens; + startTime[index] = restriction.startTime; + rollingPeriodInDays[index] = restriction.rollingPeriodInDays; + endTime[index] = restriction.endTime; + typeOfRestriction[index] = uint8(restriction.typeOfRestriction); + } + /** * @notice Returns the permissions flag that are associated with Percentage transfer Manager */ @@ -1162,4 +1205,4 @@ contract VolumeRestrictionTM is VolumeRestrictionTMStorage, ITransferManager { return allPermissions; } -} \ No newline at end of file +} diff --git a/contracts/modules/TransferManager/VolumeRestrictionTMStorage.sol b/contracts/modules/TransferManager/VolumeRestrictionTMStorage.sol index e995676a0..9eb776ff0 100644 --- a/contracts/modules/TransferManager/VolumeRestrictionTMStorage.sol +++ b/contracts/modules/TransferManager/VolumeRestrictionTMStorage.sol @@ -1,5 +1,7 @@ pragma solidity ^0.4.24; +import "../../libraries/VolumeRestrictionLib.sol"; + /** * @title Storage layout for VolumeRestrictionTM */ @@ -7,9 +9,11 @@ contract VolumeRestrictionTMStorage { enum RestrictionType { Fixed, Percentage } + enum TypeOfPeriod { MultipleDays, OneDay, Both } + struct VolumeRestriction { // If typeOfRestriction is `Percentage` then allowedTokens will be in - // the % (w.r.t to totalSupply) with a multiplier of 10**16 . else it + // the % (w.r.t to totalSupply) with a multiplier of 10**16 . else it // will be fixed amount of tokens uint256 allowedTokens; uint256 startTime; @@ -20,7 +24,7 @@ contract VolumeRestrictionTMStorage { struct BucketDetails { uint256 lastTradedDayTime; - uint256 sumOfLastPeriod; // It is the sum of transacted amount within the last rollingPeriodDays + uint256 sumOfLastPeriod; // It is the sum of transacted amount within the last rollingPeriodDays uint256 daysCovered; // No of days covered till (from the startTime of VolumeRestriction) uint256 dailyLastTradedDayTime; } @@ -40,6 +44,11 @@ contract VolumeRestrictionTMStorage { // Storing the information related to default restriction mapping(address => BucketDetails) internal defaultUserToBucket; // List of wallets that are exempted from all the restrictions applied by the this contract - mapping(address => bool) public exemptList; + /* mapping(address => bool) public exemptList; */ + // Restricted data (refernce from the VolumeRestrictionLib library ) + VolumeRestrictionLib.RestrictedData holderData; + // Holde exempt index + mapping(address => uint256) exemptIndex; + address[] public exemptAddresses; -} \ No newline at end of file +} diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index e9cdee650..ff27206a9 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -27,6 +27,7 @@ const STFactory = artifacts.require('./tokens/STFactory.sol') const DevPolyToken = artifacts.require('./helpers/PolyTokenFaucet.sol') const MockOracle = artifacts.require('./MockOracle.sol') const TokenLib = artifacts.require('./TokenLib.sol'); +const VolumeRestrictionLib = artifacts.require('./VolumeRestrictionLib.sol'); const SecurityToken = artifacts.require('./tokens/SecurityToken.sol') let BigNumber = require('bignumber.js'); @@ -141,7 +142,11 @@ module.exports = function (deployer, network, accounts) { // Deploy libraries return deployer.deploy(TokenLib, { from: PolymathAccount }); }).then(() => { + return deployer.deploy(VolumeRestrictionLib, { from: PolymathAccount }); + }).then(() => { + // Link libraries + deployer.link(VolumeRestrictionLib, VolumeRestrictionTMLogic); deployer.link(TokenLib, SecurityToken); deployer.link(TokenLib, STFactory); // A) Deploy the ModuleRegistry Contract (It contains the list of verified ModuleFactory) diff --git a/test/y_volume_restriction_tm.js b/test/y_volume_restriction_tm.js index 1075a64e4..335e76d1d 100644 --- a/test/y_volume_restriction_tm.js +++ b/test/y_volume_restriction_tm.js @@ -89,6 +89,20 @@ contract('VolumeRestrictionTransferManager', accounts => { `) } + async function printRestrictedData(data) { + let investors = data[0]; + for (let i = 0 ; i < investors.length; i++) { + console.log(` + Token holder: ${data[0][i]} + Start Time: ${data[2][i].toNumber()} + Rolling Period In Days: ${data[3][i].toNumber()} + End Time : ${data[4][i].toNumber()} + Allowed Tokens: ${web3.utils.fromWei(data[1][i].toString())} + Type of Restriction: ${data[5][i].toNumber()} + `) + } + } + async function calculateSum(rollingPeriod, tempArray) { let sum = 0; let start = 0; @@ -214,8 +228,8 @@ contract('VolumeRestrictionTransferManager', accounts => { await I_SecurityToken.mint(account_investor1, web3.utils.toWei("40", "ether"), {from: token_owner}); await I_SecurityToken.mint(account_investor2, web3.utils.toWei("30", "ether"), {from: token_owner}); await I_SecurityToken.mint(account_investor3, web3.utils.toWei("30", "ether"), {from: token_owner}); - - // Check the balance of the investors + + // Check the balance of the investors let bal1 = await I_SecurityToken.balanceOf.call(account_investor1); let bal2 = await I_SecurityToken.balanceOf.call(account_investor2); // Verifying the balances @@ -406,9 +420,11 @@ contract('VolumeRestrictionTransferManager', accounts => { from: token_owner } ); - assert.equal(tx.logs[0].args._holder, account_investor1); assert.equal(tx.logs[0].args._typeOfRestriction, 0); + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0][0], account_investor1); }); it("Should add the restriction for multiple investor -- failed because of bad owner", async() => { @@ -538,6 +554,10 @@ contract('VolumeRestrictionTransferManager', accounts => { assert.equal((await I_VolumeRestrictionTM.individualRestriction.call(account_investor2))[2].toNumber(), 3); assert.equal((await I_VolumeRestrictionTM.individualRestriction.call(account_delegate3))[2].toNumber(), 4); assert.equal((await I_VolumeRestrictionTM.individualRestriction.call(account_investor4))[2].toNumber(), 5); + + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 4); }); it("Should remove the restriction multi -- failed because of address is 0", async() => { @@ -554,6 +574,12 @@ contract('VolumeRestrictionTransferManager', accounts => { it("Should successfully remove the restriction", async() => { await I_VolumeRestrictionTM.removeIndividualRestriction(account_investor2, {from: token_owner}); assert.equal((await I_VolumeRestrictionTM.individualRestriction.call(account_investor2))[3].toNumber(), 0); + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 3); + for (let i = 0; i < data[0].length; i++) { + assert.notEqual(data[0][i], account_investor2); + } }); it("Should remove the restriction -- failed because restriction not present anymore", async() => { @@ -569,6 +595,9 @@ contract('VolumeRestrictionTransferManager', accounts => { from: token_owner } ) + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 1); }); it("Should add the restriction succesfully after the expiry of previous one for investor 1", async() => { @@ -600,9 +629,13 @@ contract('VolumeRestrictionTransferManager', accounts => { from: token_owner } ); - + assert.equal(tx.logs[1].args._holder, account_investor1); assert.equal(tx.logs[1].args._typeOfRestriction, 0); + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 1); + assert.equal(data[0][0], account_investor1); }); it("Should not successfully transact the tokens -- failed because volume is above the limit", async() => { @@ -621,14 +654,14 @@ contract('VolumeRestrictionTransferManager', accounts => { Gas estimation (Individual): ${await I_SecurityToken.transfer.estimateGas(account_investor3, web3.utils.toWei('.3'), {from: account_investor1})}` ); await I_SecurityToken.transfer(account_investor3, web3.utils.toWei('.3'), {from: account_investor1}); - // Check the balance of the investors + // Check the balance of the investors let bal1 = await I_SecurityToken.balanceOf.call(account_investor1); // Verifying the balances assert.equal(web3.utils.fromWei((bal1.toNumber()).toString()), 34.7); let data = await I_VolumeRestrictionTM.getIndividualBucketDetailsToUser.call(account_investor1); await print(data, account_investor1); - + assert.equal( (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor1, data[0])) .dividedBy(new BigNumber(10).pow(18)).toNumber(), @@ -717,6 +750,10 @@ contract('VolumeRestrictionTransferManager', accounts => { assert.equal(tx.logs[0].args._holder, account_investor3); assert.equal(tx.logs[0].args._typeOfRestriction, 0); assert.equal((tx.logs[0].args._allowedTokens).toNumber(), web3.utils.toWei("6")); + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 2); + assert.equal(data[0][1], account_investor3); let dataRestriction = await I_VolumeRestrictionTM.individualDailyRestriction.call(account_investor3); console.log(` *** Individual Daily restriction data *** @@ -738,7 +775,7 @@ contract('VolumeRestrictionTransferManager', accounts => { await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("2"), {from: account_investor3}); let data = await I_VolumeRestrictionTM.getIndividualBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); - + await increaseTime(duration.minutes(15)); console.log(` @@ -758,7 +795,7 @@ contract('VolumeRestrictionTransferManager', accounts => { it("Should fail to transfer more tokens --because of the above limit", async() => { await catchRevert( I_SecurityToken.transfer(account_investor2, web3.utils.toWei(".1"), {from: account_investor3}) - ); + ); }); it("Should try to send after the one day completion", async() => { @@ -793,6 +830,11 @@ contract('VolumeRestrictionTransferManager', accounts => { assert.equal(tx.logs[0].args._holder, account_investor1); assert.equal((tx.logs[0].args._typeOfRestriction).toNumber(), 1); assert.equal((tx.logs[0].args._allowedTokens).dividedBy(new BigNumber(10).pow(16)).toNumber(), 5); + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 3); + assert.equal(data[0][2], account_investor3); + assert.equal(data[0][0], account_investor1); let dataRestriction = await I_VolumeRestrictionTM.individualDailyRestriction.call(account_investor1); console.log(` *** Individual Daily restriction data *** @@ -813,7 +855,7 @@ contract('VolumeRestrictionTransferManager', accounts => { ); await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("2"), {from: account_investor1}); - // Check the balance of the investors + // Check the balance of the investors let bal1 = await I_SecurityToken.balanceOf.call(account_investor1); // Verifying the balances assert.equal(web3.utils.fromWei((bal1.toNumber()).toString()), 32.7); @@ -854,9 +896,15 @@ contract('VolumeRestrictionTransferManager', accounts => { from: token_owner } ); - + assert.equal(tx.logs[0].args._holder, account_investor3); assert.equal(tx.logs[0].args._typeOfRestriction, 1); + + let data = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(data); + assert.equal(data[0].length, 4); + assert.equal(data[0][2], account_investor3); + assert.equal(data[0][0], account_investor1); }); it("Should transfer the token by the investor 3 with in the (Individual + Individual daily limit)", async() => { @@ -868,11 +916,11 @@ contract('VolumeRestrictionTransferManager', accounts => { console.log(` Gas estimation (Individual + Individual daily): ${await I_SecurityToken.transfer.estimateGas(account_investor2, web3.utils.toWei("4"), {from: account_investor3})}` ); - // Check the balance of the investors + // Check the balance of the investors let bal1 = await I_SecurityToken.balanceOf.call(account_investor3); await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("4"), {from: account_investor3}); tempArray3.push(4); - // Check the balance of the investors + // Check the balance of the investors let bal2 = await I_SecurityToken.balanceOf.call(account_investor3); // Verifying the balances assert.equal(web3.utils.fromWei(((bal1.minus(bal2)).toNumber()).toString()), 4); @@ -910,6 +958,11 @@ contract('VolumeRestrictionTransferManager', accounts => { // remove the Individual daily restriction let tx = await I_VolumeRestrictionTM.removeIndividualDailyRestriction(account_investor3, {from: token_owner}); assert.equal(tx.logs[0].args._holder, account_investor3); + let dataAdd = await I_VolumeRestrictionTM.getRestrictedData.call(); + await printRestrictedData(dataAdd); + assert.equal(dataAdd[0].length, 3); + assert.equal(dataAdd[0][0], account_investor1); + assert.equal(dataAdd[0][2], account_investor3); let startTime = (await I_VolumeRestrictionTM.individualRestriction.call(account_investor3))[1].toNumber(); @@ -1000,7 +1053,7 @@ contract('VolumeRestrictionTransferManager', accounts => { ) ); }); - + it("Should modify the individual daily restriction", async() => { await I_VolumeRestrictionTM.modifyIndividualDailyRestriction( account_investor3, @@ -1105,7 +1158,7 @@ contract('VolumeRestrictionTransferManager', accounts => { }); it("Should fail to transact tokens more than the allowed in the second rolling period", async() => { - await increaseTime(duration.days(4)); + await increaseTime(duration.days(4)); let i for (i = 0; i < 3; i++) { tempArray3.push(0); @@ -1126,7 +1179,7 @@ contract('VolumeRestrictionTransferManager', accounts => { let allowedAmount = (tempArray3[0] + 1); //sell tokens upto the limit await I_SecurityToken.transfer(account_investor2, web3.utils.toWei(allowedAmount.toString()), {from: account_investor3}); - + tempArray3.push(allowedAmount); let data = await I_VolumeRestrictionTM.getIndividualBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); @@ -1155,11 +1208,11 @@ contract('VolumeRestrictionTransferManager', accounts => { //sell tokens upto the limit await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("7"), {from: account_investor3}); - + tempArray3.push(7) let data = await I_VolumeRestrictionTM.getIndividualBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); - + // get the trade amount using the timestamp let amt = (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor3, data[0].toNumber())) .dividedBy(new BigNumber(10).pow(18)).toNumber(); @@ -1190,7 +1243,7 @@ contract('VolumeRestrictionTransferManager', accounts => { let data = await I_VolumeRestrictionTM.getIndividualBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); - + // get the trade amount using the timestamp let amt = (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor3, data[0].toNumber())) .dividedBy(new BigNumber(10).pow(18)).toNumber(); @@ -1211,7 +1264,7 @@ contract('VolumeRestrictionTransferManager', accounts => { }); describe("Test cases for the Default restrictions", async() => { - + it("Should add the investor 4 in the whitelist", async() => { await I_GeneralTransferManager.modifyWhitelist( account_investor4, @@ -1261,10 +1314,10 @@ contract('VolumeRestrictionTransferManager', accounts => { let startTimedaily = (await I_VolumeRestrictionTM.defaultDailyRestriction.call())[1].toNumber(); //sell tokens upto the limit await I_SecurityToken.transfer(account_investor2, web3.utils.toWei("3.57"), {from: account_investor4}); - + let data = await I_VolumeRestrictionTM.getDefaultBucketDetailsToUser.call(account_investor4); await print(data, account_investor3); - + // get the trade amount using the timestamp let amt = (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor4, data[3].toNumber())) .dividedBy(new BigNumber(10).pow(18)).toNumber(); @@ -1324,7 +1377,7 @@ contract('VolumeRestrictionTransferManager', accounts => { let data = await I_VolumeRestrictionTM.getDefaultBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); - + // get the trade amount using the timestamp let amt = (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor3, data[0].toNumber())) .dividedBy(new BigNumber(10).pow(18)).toNumber(); @@ -1380,7 +1433,7 @@ contract('VolumeRestrictionTransferManager', accounts => { let data = await I_VolumeRestrictionTM.getDefaultBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); - + // get the trade amount using the timestamp let amt = (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor3, data[0].toNumber())) .dividedBy(new BigNumber(10).pow(18)).toNumber(); @@ -1437,7 +1490,7 @@ contract('VolumeRestrictionTransferManager', accounts => { let data = await I_VolumeRestrictionTM.getDefaultBucketDetailsToUser.call(account_investor3); await print(data, account_investor3); - + // get the trade amount using the timestamp let amt = (await I_VolumeRestrictionTM.getTotalTradedByUser.call(account_investor3, data[0].toNumber())) .dividedBy(new BigNumber(10).pow(18)).toNumber(); @@ -1461,12 +1514,63 @@ contract('VolumeRestrictionTransferManager', accounts => { it("Should add the token holder in the exemption list", async() => { await I_VolumeRestrictionTM.changeExemptWalletList(account_investor4, true, {from: token_owner}); + console.log(await I_VolumeRestrictionTM.getExemptAddress.call()); let beforeBal = await I_SecurityToken.balanceOf.call(account_investor4); await I_SecurityToken.transfer(account_investor3, web3.utils.toWei("3"), {from: account_investor4}); let afterBal = await I_SecurityToken.balanceOf.call(account_investor4); let diff = beforeBal.minus(afterBal); assert.equal(web3.utils.fromWei((diff.toNumber()).toString()), 3); }); + + it("Should add multiple token holders to exemption list and check the getter value", async() => { + let holders = [account_investor1, account_investor3, account_investor2, account_delegate2]; + let change = [true, true, true, true]; + for (let i = 0; i < holders.length; i++) { + await I_VolumeRestrictionTM.changeExemptWalletList(holders[i], change[i], {from: token_owner}); + } + let data = await I_VolumeRestrictionTM.getExemptAddress.call(); + assert.equal(data.length, 5); + assert.equal(data[0], account_investor4); + assert.equal(data[1], account_investor1); + assert.equal(data[2], account_investor3); + assert.equal(data[3], account_investor2); + assert.equal(data[4], account_delegate2); + }); + + it("Should unexempt a particular address", async() => { + await I_VolumeRestrictionTM.changeExemptWalletList(account_investor1, false, {from: token_owner}); + let data = await I_VolumeRestrictionTM.getExemptAddress.call(); + assert.equal(data.length, 4); + assert.equal(data[0], account_investor4); + assert.equal(data[1], account_delegate2); + assert.equal(data[2], account_investor3); + assert.equal(data[3], account_investor2); + }); + + it("Should fail to unexempt the same address again", async() => { + await catchRevert( + I_VolumeRestrictionTM.changeExemptWalletList(account_investor1, false, {from: token_owner}) + ); + }); + + it("Should delete the last element of the exemption list", async() => { + await I_VolumeRestrictionTM.changeExemptWalletList(account_investor2, false, {from: token_owner}); + let data = await I_VolumeRestrictionTM.getExemptAddress.call(); + assert.equal(data.length, 3); + assert.equal(data[0], account_investor4); + assert.equal(data[1], account_delegate2); + assert.equal(data[2], account_investor3); + }); + + it("Should delete multiple investor from the exemption list", async() => { + let holders = [account_delegate2, account_investor4, account_investor3]; + let change = [false, false, false]; + for (let i = 0; i < holders.length; i++) { + await I_VolumeRestrictionTM.changeExemptWalletList(holders[i], change[i], {from: token_owner}); + } + let data = await I_VolumeRestrictionTM.getExemptAddress.call(); + assert.equal(data.length, 0); + }); }); describe("Test for modify functions", async() => { @@ -1552,5 +1656,5 @@ contract('VolumeRestrictionTransferManager', accounts => { assert.equal(web3.utils.toAscii(tags[0]).replace(/\u0000/g, ''), "Maximum Volume"); }); }); - -}); \ No newline at end of file + +});