Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CLI/commands/ST20Generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const MODULES_TYPES = {
PERMISSION: 1,
TRANSFER: 2,
STO: 3,
DIVIDENDS: 4
DIVIDENDS: 4,
BURN: 5
}

const cappedSTOFee = 20000;
Expand Down
3 changes: 2 additions & 1 deletion CLI/commands/dividends_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ const MODULES_TYPES = {
PERMISSION: 1,
TRANSFER: 2,
STO: 3,
DIVIDENDS: 4
DIVIDENDS: 4,
BURN: 5
}

// App flow
Expand Down
12 changes: 11 additions & 1 deletion CLI/commands/helpers/contract_abis.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ let stoInterfaceABI;
let cappedSTOABI;
let usdTieredSTOABI;
let generalTransferManagerABI;
let generalPermissionManagerABI;
let polyTokenABI;
let cappedSTOFactoryABI;
let usdTieredSTOFactoryABI;
let erc20DividendCheckpointABI;
let etherDividendCheckpointABI;
let moduleInterfaceABI;
let ownableABI;
let moduleFactoryABI;

Expand All @@ -25,16 +27,18 @@ try {
cappedSTOABI = JSON.parse(require('fs').readFileSync('./build/contracts/CappedSTO.json').toString()).abi;
usdTieredSTOABI = JSON.parse(require('fs').readFileSync('./build/contracts/USDTieredSTO.json').toString()).abi;
generalTransferManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/GeneralTransferManager.json').toString()).abi;
generalPermissionManagerABI = JSON.parse(require('fs').readFileSync('./build/contracts/GeneralPermissionManager.json').toString()).abi;
polyTokenABI = JSON.parse(require('fs').readFileSync('./build/contracts/PolyTokenFaucet.json').toString()).abi;
cappedSTOFactoryABI = JSON.parse(require('fs').readFileSync('./build/contracts/CappedSTOFactory.json').toString()).abi;
usdTieredSTOFactoryABI = JSON.parse(require('fs').readFileSync('./build/contracts/USDTieredSTOFactory.json').toString()).abi;
erc20DividendCheckpointABI = JSON.parse(require('fs').readFileSync('./build/contracts/ERC20DividendCheckpoint.json').toString()).abi;
etherDividendCheckpointABI = JSON.parse(require('fs').readFileSync('./build/contracts/EtherDividendCheckpoint.json').toString()).abi;
moduleInterfaceABI = JSON.parse(require('fs').readFileSync('./build/contracts/IModule.json').toString()).abi;
ownableABI = JSON.parse(require('fs').readFileSync('./build/contracts/Ownable.json').toString()).abi;
moduleFactoryABI = JSON.parse(require('fs').readFileSync('./build/contracts/ModuleFactory.json').toString()).abi;
} catch (err) {
console.log('\x1b[31m%s\x1b[0m',"Couldn't find contracts' artifacts. Make sure you ran truffle compile first");
return;
throw err;
}

module.exports = {
Expand Down Expand Up @@ -65,6 +69,9 @@ module.exports = {
generalTransferManager: function () {
return generalTransferManagerABI;
},
generalPermissionManager: function () {
return generalPermissionManagerABI;
},
polyToken: function () {
return polyTokenABI;
},
Expand All @@ -80,6 +87,9 @@ module.exports = {
etherDividendCheckpoint: function () {
return etherDividendCheckpointABI;
},
moduleInterface: function () {
return moduleInterfaceABI;
},
ownable: function () {
return ownableABI;
},
Expand Down
222 changes: 222 additions & 0 deletions CLI/commands/permission_manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
var readlineSync = require('readline-sync');
var chalk = require('chalk');
var common = require('./common/common_functions');
var global = require('./common/global');
var contracts = require('./helpers/contract_addresses');
var abis = require('./helpers/contract_abis');

// App flow
let tokenSymbol;
let securityTokenRegistry;
let securityToken;
let generalPermissionManager;

const MODULES_TYPES = {
PERMISSION: 1,
TRANSFER: 2,
STO: 3,
DIVIDEND: 4,
BURN: 5
}

async function executeApp(remoteNetwork) {
await global.initialize(remoteNetwork);

common.logAsciiBull();
console.log("***********************************************");
console.log("Welcome to the Command-Line Permission Manager.");
console.log("***********************************************");
console.log("Issuer Account: " + Issuer.address + "\n");

await setup();
try {
await selectST();
await addPermissionModule();
await changePermissionStep();
} catch (err) {
console.log(err);
return;
}
};

async function setup(){
try {
let securityTokenRegistryAddress = await contracts.securityTokenRegistry();
let securityTokenRegistryABI = abis.securityTokenRegistry();
securityTokenRegistry = new web3.eth.Contract(securityTokenRegistryABI, securityTokenRegistryAddress);
securityTokenRegistry.setProvider(web3.currentProvider);
} catch (err) {
console.log(err)
console.log('\x1b[31m%s\x1b[0m',"There was a problem getting the contracts. Make sure they are deployed to the selected network.");
process.exit(0);
}
}

async function selectST() {
if (!tokenSymbol)
tokenSymbol = readlineSync.question('Enter the token symbol: ');

let result = await securityTokenRegistry.methods.getSecurityTokenAddress(tokenSymbol).call();
if (result == "0x0000000000000000000000000000000000000000") {
tokenSymbol = undefined;
console.log(chalk.red(`Token symbol provided is not a registered Security Token.`));
await selectST();
} else {
let securityTokenABI = abis.securityToken();
securityToken = new web3.eth.Contract(securityTokenABI,result);
}
}

async function addPermissionModule() {
let generalPermissionManagerAddress;
let result = await securityToken.methods.getModulesByName(web3.utils.toHex('GeneralPermissionManager')).call();
if (result.length == 0) {
console.log(chalk.red(`General Permission Manager is not attached.`));
if (readlineSync.keyInYNStrict('Do you want to add General Permission Manager Module to your Security Token?')) {
let permissionManagerFactoryAddress = await contracts.getModuleFactoryAddressByName(securityToken.options.address, MODULES_TYPES.PERMISSION, 'GeneralPermissionManager');
let addModuleAction = securityToken.methods.addModule(permissionManagerFactoryAddress, web3.utils.fromAscii('', 16), 0, 0);
let receipt = await common.sendTransaction(Issuer, addModuleAction, defaultGasPrice);
let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'ModuleAdded');
console.log(`Module deployed at address: ${event._module}`);
generalPermissionManagerAddress = event._module;
} else {
process.exit(0);
}
} else {
generalPermissionManagerAddress = result[0];
}

let generalPermissionManagerABI = abis.generalPermissionManager();
generalPermissionManager = new web3.eth.Contract(generalPermissionManagerABI, generalPermissionManagerAddress);
generalPermissionManager.setProvider(web3.currentProvider);
}

async function changePermissionStep() {
console.log('\n\x1b[34m%s\x1b[0m',"Permission Manager - Change Permission");
let selectedDelegate = await selectDelegate();
let selectedModule = await selectModule();
let selectedPermission = await selectPermission(selectedModule.permissions);
let isValid = isPermissionValid();
await changePermission(selectedDelegate, selectedModule.address, selectedPermission, isValid);
}

// Helper functions
async function selectDelegate() {
let result;
let delegates = await getDelegates();

let options = ['Add new delegate'];
options = options.concat(delegates.map(function(d) {
return `Account: ${d.address}
Details: ${d.details}`
}));

let index = readlineSync.keyInSelect(options, 'Select a delegate:', {cancel: false});
if (index == 0) {
let newDelegate = await addNewDelegate();
result = newDelegate;
} else {
result = delegates[index - 1].address;
}

return result;
}

async function selectModule() {
let modules = await getModulesWithPermissions();
let options = modules.map(function(m) {
return m.name;
});
let index = readlineSync.keyInSelect(options, 'Select a module:', {cancel: false});
return modules[index];
}

async function selectPermission(permissions) {
let options = permissions.map(function(p) {
return p
});
let index = readlineSync.keyInSelect(options, 'Select a permission:', {cancel: false});
return permissions[index];
}

function isPermissionValid() {
let options = ['Grant permission', 'Revoke permission'];
let index = readlineSync.keyInSelect(options, 'What do you want to do?', {cancel: false});
return index == 0;
}

async function changePermission(delegate, moduleAddress, permission, isValid) {
let changePermissionAction = generalPermissionManager.methods.changePermission(delegate, moduleAddress, web3.utils.asciiToHex(permission), isValid);
let receipt = await common.sendTransaction(Issuer, changePermissionAction, defaultGasPrice, 0, 1.5);
common.getEventFromLogs(generalPermissionManager._jsonInterface, receipt.logs, 'ChangePermission');
console.log(`Permission changed succesfully,`);
}

async function getDelegates() {
let result = [];
/*
let events = await generalPermissionManager.getPastEvents('LogAddPermission', { fromBlock: 0});
for (let event of events) {
let delegate = {};
delegate.address = event.returnValues._delegate;
delegate.details = web3.utils.hexToAscii(event.returnValues._details);
result.push(delegate);
}
*/
let delegates = await generalPermissionManager.methods.getAllDelegates().call();
for (let d of delegates) {
let delegate = {};
delegate.address = d;
delegate.details = web3.utils.hexToAscii(await generalPermissionManager.methods.delegateDetails(d).call());
result.push(delegate);
}
return result;
}

async function addNewDelegate() {
let newDelegate = readlineSync.question('Enter the delegate address: ', {
limit: function (input) {
return web3.utils.isAddress(input);
},
limitMessage: "Must be a valid address"
});
let details = readlineSync.question('Enter the delegate details (i.e `Belongs to financial firm`): ', {
limit: function(input) {
return input.length > 0;
},
limitMessage: "Must be a valid string"
});
let addPermissionAction = generalPermissionManager.methods.addDelegate(newDelegate, web3.utils.asciiToHex(details));
let receipt = await common.sendTransaction(Issuer, addPermissionAction, defaultGasPrice);
let event = common.getEventFromLogs(generalPermissionManager._jsonInterface, receipt.logs, 'AddDelegate');
console.log(`Delegate added succesfully: ${event._delegate} - ${event._details}`);
return event._delegate;
}

async function getModulesWithPermissions() {
let modules = [];
let moduleABI = abis.moduleInterface();

for (const type in MODULES_TYPES) {
let modulesAttached = await securityToken.methods.getModulesByType(MODULES_TYPES[type]).call();
for (const m of modulesAttached) {
let contractTemp = new web3.eth.Contract(moduleABI, m);
let permissions = await contractTemp.methods.getPermissions().call();
if (permissions.length > 0) {
modules.push({
name: web3.utils.hexToAscii((await securityToken.methods.getModule(m).call())[0]),
address: m,
permissions: permissions.map(function (p) { return web3.utils.hexToAscii(p) })
})
}
}
}

return modules;
}

module.exports = {
executeApp: async function(remoteNetwork) {
return executeApp(remoteNetwork);
}
}
9 changes: 9 additions & 0 deletions CLI/polymath-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var dividends_manager = require('./commands/dividends_manager');
var transfer_manager = require('./commands/transfer_manager');
var contract_manager = require('./commands/contract_manager');
var strMigrator = require('./commands/strMigrator');
var permission_manager = require('./commands/permission_manager');
var program = require('commander');
const yaml = require('js-yaml');
const fs = require('fs');
Expand Down Expand Up @@ -142,6 +143,14 @@ program
await strMigrator.executeApp(toStrAddress, fromTrAddress, fromStrAddress, program.remoteNode);
});

program
.command('permission_manager')
.alias('pm')
.description('Runs permission_manager')
.action(async function() {
await permission_manager.executeApp(program.remoteNode);
});

program.parse(process.argv);

if (typeof program.commands.length == 0) {
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ You can access Ethereum via the Infura load-balanced nodes. You have to save you
node CLI/polymath-cli faucet --remote-node kovan
```
3. Connected to a local private test network using `ganache-cli`.
You have to save the private key for the first account generated by ganache into `./privKeyLocal`.
You have to save the private key for the one of the accounts generated by ganache into `./privKeyLocal`.


## Poly Faucet
Expand Down