Skip to content

Commit 325d7a9

Browse files
authored
Merge pull request #447 from PolymathNetwork/cli-count-and-percentage-TM
[CLI] Add count and percentage tm
2 parents c8a4f56 + 343b432 commit 325d7a9

File tree

5 files changed

+181
-146
lines changed

5 files changed

+181
-146
lines changed

CLI/commands/common/csv_shared.js

Lines changed: 0 additions & 82 deletions
This file was deleted.

CLI/commands/common/csv_sync.js

Lines changed: 0 additions & 39 deletions
This file was deleted.

CLI/commands/helpers/contract_abis.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ let cappedSTOABI;
88
let usdTieredSTOABI;
99
let generalTransferManagerABI;
1010
let manualApprovalTransferManagerABI;
11+
let countTransferManagerABI;
12+
let percentageTransferManagerABI;
1113
let generalPermissionManagerABI;
1214
let polyTokenABI;
1315
let cappedSTOFactoryABI;
@@ -31,6 +33,8 @@ try {
3133
usdTieredSTOABI = JSON.parse(require('fs').readFileSync('./build/contracts/USDTieredSTO.json').toString()).abi;
3234
generalTransferManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/GeneralTransferManager.json').toString()).abi;
3335
manualApprovalTransferManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/ManualApprovalTransferManager.json').toString()).abi;
36+
countTransferManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/CountTransferManager.json').toString()).abi;
37+
percentageTransferManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/PercentageTransferManager.json').toString()).abi;
3438
generalPermissionManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/GeneralPermissionManager.json').toString()).abi;
3539
polyTokenABI = JSON.parse(require('fs').readFileSync('./build/contracts/PolyTokenFaucet.json').toString()).abi;
3640
cappedSTOFactoryABI = JSON.parse(require('fs').readFileSync('./build/contracts/CappedSTOFactory.json').toString()).abi;
@@ -78,6 +82,12 @@ module.exports = {
7882
manualApprovalTransferManager: function () {
7983
return manualApprovalTransferManagerABI;
8084
},
85+
countTransferManager: function () {
86+
return countTransferManagerABI;
87+
},
88+
percentageTransferManager: function () {
89+
return percentageTransferManagerABI;
90+
},
8191
generalPermissionManager: function () {
8292
return generalPermissionManagerABI;
8393
},

CLI/commands/transfer_manager.js

Lines changed: 161 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const csvParse = require('./helpers/csv');
1010
///////////////////
1111
// Constants
1212
const WHITELIST_DATA_CSV = './CLI/data/Transfer/GTM/whitelist_data.csv';
13+
const PERCENTAGE_WHITELIST_DATA_CSV = './CLI/data/Transfer/PercentageTM/whitelist_data.csv';
1314

1415
// App flow
1516
let tokenSymbol;
@@ -184,7 +185,7 @@ async function configExistingModules(tmModules) {
184185
let options = tmModules.map(m => `${m.name} at ${m.address}`);
185186
let index = readlineSync.keyInSelect(options, 'Which module do you want to config? ', { cancel: 'Return' });
186187
console.log('Selected:', index != -1 ? options[index] : 'Return', '\n');
187-
let moduleNameSelected = tmModules[index].name;
188+
let moduleNameSelected = index != -1 ? tmModules[index].name : 'Return';
188189

189190
switch (moduleNameSelected) {
190191
case 'GeneralTransferManager':
@@ -197,16 +198,15 @@ async function configExistingModules(tmModules) {
197198
currentTransferManager.setProvider(web3.currentProvider);
198199
await manualApprovalTransferManager();
199200
break;
200-
case 'PercentageTransferManager':
201-
//await percentageTransferManager();
202-
console.log(chalk.red(`
203-
*********************************
204-
This option is not yet available.
205-
*********************************`
206-
));
207-
break;
208201
case 'CountTransferManager':
209-
//await countTransferManager();
202+
currentTransferManager = new web3.eth.Contract(abis.countTransferManager(), tmModules[index].address);
203+
currentTransferManager.setProvider(web3.currentProvider);
204+
await countTransferManager();
205+
break;
206+
case 'PercentageTransferManager':
207+
currentTransferManager = new web3.eth.Contract(abis.percentageTransferManager(), tmModules[index].address);
208+
currentTransferManager.setProvider(web3.currentProvider);
209+
await percentageTransferManager();
210210
break;
211211
case 'SingleTradeVolumeRestrictionTM':
212212
//currentTransferManager = new web3.eth.Contract(abis.singleTradeVolumeRestrictionTM(), tmModules[index].address);
@@ -230,26 +230,34 @@ async function configExistingModules(tmModules) {
230230
}
231231

232232
async function addTransferManagerModule() {
233-
let options = ['GeneralTransferManager', 'ManualApprovalTransferManager'/*, 'PercentageTransferManager',
234-
'CountTransferManager', 'SingleTradeVolumeRestrictionTM', 'LookupVolumeRestrictionTM'*/];
233+
let options = [
234+
'GeneralTransferManager',
235+
'ManualApprovalTransferManager',
236+
'CountTransferManager',
237+
'PercentageTransferManager',
238+
//'SingleTradeVolumeRestrictionTM',
239+
//'LookupVolumeRestrictionTM'*/
240+
];
235241

236242
let index = readlineSync.keyInSelect(options, 'Which Transfer Manager module do you want to add? ', { cancel: 'Return' });
237243
if (index != -1 && readlineSync.keyInYNStrict(`Are you sure you want to add ${options[index]} module?`)) {
238244
let bytes = web3.utils.fromAscii('', 16);
239245
switch (options[index]) {
240-
case 'PercentageTransferManager':
241-
console.log(chalk.red(`
242-
*********************************
243-
This option is not yet available.
244-
*********************************`
245-
));
246-
break;
247246
case 'CountTransferManager':
248-
console.log(chalk.red(`
249-
*********************************
250-
This option is not yet available.
251-
*********************************`
252-
));
247+
let maxHolderCount = readlineSync.question('Enter the maximum no. of holders the SecurityToken is allowed to have: ');
248+
let configureCountTM = abis.countTransferManager().find(o => o.name === 'configure' && o.type === 'function');
249+
bytes = web3.eth.abi.encodeFunctionCall(configureCountTM, [maxHolderCount]);
250+
break;
251+
case 'PercentageTransferManager':
252+
let maxHolderPercentage = toWeiPercentage(readlineSync.question('Enter the maximum amount of tokens in percentage that an investor can hold: ', {
253+
limit: function (input) {
254+
return (parseInt(input) > 0 && parseInt(input) <= 100);
255+
},
256+
limitMessage: "Must be greater than 0 and less than 100"
257+
}));
258+
let allowPercentagePrimaryIssuance = readlineSync.keyInYNStrict(`Do you want to ignore transactions which are part of the primary issuance? `);
259+
let configurePercentageTM = abis.percentageTransferManager().find(o => o.name === 'configure' && o.type === 'function');
260+
bytes = web3.eth.abi.encodeFunctionCall(configurePercentageTM, [maxHolderPercentage, allowPercentagePrimaryIssuance]);
253261
break;
254262
case 'SingleTradeVolumeRestrictionTM':
255263
/*
@@ -511,7 +519,7 @@ async function modifyWhitelistInBatch() {
511519
console.log(`Batch ${batch + 1} - Attempting to modify whitelist to accounts: \n\n`, investorArray[batch], '\n');
512520
let action = await currentTransferManager.methods.modifyWhitelistMulti(investorArray[batch], fromTimesArray[batch], toTimesArray[batch], expiryTimeArray[batch], canBuyFromSTOArray[batch]);
513521
let receipt = await common.sendTransaction(action);
514-
console.log(chalk.green('Whitelist transaction was successful.'));
522+
console.log(chalk.green('Modify whitelist transaction was successful.'));
515523
console.log(`${receipt.gasUsed} gas used.Spent: ${web3.utils.fromWei((new web3.utils.BN(receipt.gasUsed)).mul(new web3.utils.BN(defaultGasPrice)))} ETH`);
516524
}
517525
}
@@ -691,6 +699,134 @@ async function getManualBlocking(_from, _to) {
691699
return result;
692700
}
693701

702+
async function countTransferManager() {
703+
console.log(chalk.blue(`Count Transfer Manager at ${currentTransferManager.options.address}`), '\n');
704+
705+
// Show current data
706+
let displayMaxHolderCount = await currentTransferManager.methods.maxHolderCount().call();
707+
708+
console.log(`- Max holder count: ${displayMaxHolderCount}`);
709+
710+
let options = ['Change max holder count']
711+
let index = readlineSync.keyInSelect(options, 'What do you want to do?', { cancel: 'Return' });
712+
let optionSelected = options[index];
713+
console.log('Selected:', index != -1 ? optionSelected : 'Return', '\n');
714+
switch (optionSelected) {
715+
case 'Change max holder count':
716+
let maxHolderCount = readlineSync.question('Enter the maximum no. of holders the SecurityToken is allowed to have: ');
717+
let changeHolderCountAction = currentTransferManager.methods.changeHolderCount(maxHolderCount);
718+
let changeHolderCountReceipt = await common.sendTransaction(changeHolderCountAction);
719+
let changeHolderCountEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, changeHolderCountReceipt.logs, 'ModifyHolderCount');
720+
console.log(chalk.green(`Max holder count has been set to ${changeHolderCountEvent._newHolderCount} sucessfully!`));
721+
break;
722+
}
723+
}
724+
725+
async function percentageTransferManager() {
726+
console.log(chalk.blue(`Percentage Transfer Manager at ${currentTransferManager.options.address}`), '\n');
727+
728+
// Show current data
729+
let displayMaxHolderPercentage = await currentTransferManager.methods.maxHolderPercentage().call();
730+
let displayAllowPrimaryIssuance = await currentTransferManager.methods.allowPrimaryIssuance().call();
731+
732+
console.log(`- Max holder percentage: ${fromWeiPercentage(displayMaxHolderPercentage)}%`);
733+
console.log(`- Allow primary issuance: ${displayAllowPrimaryIssuance ? `YES` : `NO`}`);
734+
735+
let options = ['Change max holder percentage', 'Check if investor is whitelisted', 'Modify whitelist', 'Modify whitelist from CSV'];
736+
if (displayAllowPrimaryIssuance) {
737+
options.push('Disallow primary issuance');
738+
} else {
739+
options.push('Allow primary issuance');
740+
}
741+
let index = readlineSync.keyInSelect(options, 'What do you want to do?', { cancel: 'Return' });
742+
let optionSelected = options[index];
743+
console.log('Selected:', index != -1 ? optionSelected : 'Return', '\n');
744+
switch (optionSelected) {
745+
case 'Change max holder percentage':
746+
let maxHolderPercentage = toWeiPercentage(readlineSync.question('Enter the maximum amount of tokens in percentage that an investor can hold: ', {
747+
limit: function (input) {
748+
return (parseInt(input) > 0 && parseInt(input) <= 100);
749+
},
750+
limitMessage: "Must be greater than 0 and less than 100"
751+
}));
752+
let changeHolderPercentageAction = currentTransferManager.methods.changeHolderPercentage(maxHolderPercentage);
753+
let changeHolderPercentageReceipt = await common.sendTransaction(changeHolderPercentageAction);
754+
let changeHolderPercentageEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, changeHolderPercentageReceipt.logs, 'ModifyHolderPercentage');
755+
console.log(chalk.green(`Max holder percentage has been set to ${fromWeiPercentage(changeHolderPercentageEvent._newHolderPercentage)} successfully!`));
756+
break;
757+
case 'Check if investor is whitelisted':
758+
let investorToCheck = readlineSync.question('Enter the address of the investor: ', {
759+
limit: function (input) {
760+
return web3.utils.isAddress(input);
761+
},
762+
limitMessage: "Must be a valid address"
763+
});
764+
let isWhitelisted = await currentTransferManager.methods.whitelist(investorToCheck).call();
765+
if (isWhitelisted) {
766+
console.log(chalk.green(`${investorToCheck} is whitelisted!`));
767+
} else {
768+
console.log(chalk.yellow(`${investorToCheck} is not whitelisted!`));
769+
}
770+
break;
771+
case 'Modify whitelist':
772+
let valid = !!readlineSync.keyInSelect(['Remove investor from whitelist', 'Add investor to whitelist'], 'How do you want to do? ', { cancel: false });
773+
let investorToWhitelist = readlineSync.question('Enter the address of the investor: ', {
774+
limit: function (input) {
775+
return web3.utils.isAddress(input);
776+
},
777+
limitMessage: "Must be a valid address"
778+
});
779+
let modifyWhitelistAction = currentTransferManager.methods.modifyWhitelist(investorToWhitelist, valid);
780+
let modifyWhitelistReceipt = await common.sendTransaction(modifyWhitelistAction);
781+
let modifyWhitelistEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, modifyWhitelistReceipt.logs, 'ModifyWhitelist');
782+
if (modifyWhitelistEvent._valid) {
783+
console.log(chalk.green(`${modifyWhitelistEvent._investor} has been added to the whitelist sucessfully!`));
784+
} else {
785+
console.log(chalk.green(`${modifyWhitelistEvent._investor} has been removed from the whitelist sucessfully!`));
786+
}
787+
break;
788+
case 'Modify whitelist from CSV':
789+
let csvFilePath = readlineSync.question(`Enter the path for csv data file (${PERCENTAGE_WHITELIST_DATA_CSV}): `, {
790+
defaultInput: PERCENTAGE_WHITELIST_DATA_CSV
791+
});
792+
let batchSize = readlineSync.question(`Enter the max number of records per transaction or batch size (${gbl.constants.DEFAULT_BATCH_SIZE}): `, {
793+
limit: function (input) {
794+
return parseInt(input) > 0;
795+
},
796+
limitMessage: 'Must be greater than 0',
797+
defaultInput: gbl.constants.DEFAULT_BATCH_SIZE
798+
});
799+
let parsedData = csvParse(csvFilePath);
800+
let validData = parsedData.filter(row => web3.utils.isAddress(row[0]) && typeof row[1] === 'boolean');
801+
let invalidRows = parsedData.filter(row => !validData.includes(row));
802+
if (invalidRows.length > 0) {
803+
console.log(chalk.red(`The following lines from csv file are not valid: ${invalidRows.map(r => parsedData.indexOf(r) + 1).join(',')}`));
804+
}
805+
let batches = common.splitIntoBatches(validData, batchSize);
806+
let [investorArray, isWhitelistedArray] = common.transposeBatches(batches);
807+
for (let batch = 0; batch < batches.length; batch++) {
808+
console.log(`Batch ${batch + 1} - Attempting to modify whitelist accounts:\n\n`, investorArray[batch], '\n');
809+
let action = await currentTransferManager.methods.modifyWhitelistMulti(investorArray[batch], isWhitelistedArray[batch]);
810+
let receipt = await common.sendTransaction(action);
811+
console.log(chalk.green('Modify whitelist transaction was successful.'));
812+
console.log(`${receipt.gasUsed} gas used. Spent: ${web3.utils.fromWei((new web3.utils.BN(receipt.gasUsed)).mul(new web3.utils.BN(defaultGasPrice)))} ETH`);
813+
}
814+
break;
815+
case 'Allow primary issuance':
816+
case 'Disallow primary issuance':
817+
let setAllowPrimaryIssuanceAction = currentTransferManager.methods.setAllowPrimaryIssuance(!displayAllowPrimaryIssuance);
818+
let setAllowPrimaryIssuanceReceipt = await common.sendTransaction(setAllowPrimaryIssuanceAction);
819+
let setAllowPrimaryIssuanceEvent = common.getEventFromLogs(currentTransferManager._jsonInterface, setAllowPrimaryIssuanceReceipt.logs, 'SetAllowPrimaryIssuance');
820+
if (setAllowPrimaryIssuanceEvent._allowPrimaryIssuance) {
821+
console.log(chalk.green(`Transactions which are part of the primary issuance will be ignored!`));
822+
} else {
823+
console.log(chalk.green(`Transactions which are part of the primary issuance will NOT be ignored!`));
824+
}
825+
break;
826+
827+
}
828+
}
829+
694830
async function singleTradeVolumeRestrictionTM() {
695831
console.log(chalk.blue(`Single Trade Volume Restriction Transfer Manager at ${currentTransferManager.options.address} `));
696832
console.log();

0 commit comments

Comments
 (0)