From 8c0e23510fe7cb7d9eb002435ed51df87223a91d Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 3 Oct 2018 10:53:41 -0300 Subject: [PATCH 1/6] CLI fix for whitelist command --- CLI/polymath-cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLI/polymath-cli.js b/CLI/polymath-cli.js index 43d6c4c88..d8b60e31a 100644 --- a/CLI/polymath-cli.js +++ b/CLI/polymath-cli.js @@ -91,7 +91,7 @@ program .alias('w') .description('Mass-update a whitelist of allowed/known investors') .action(async function(tokenSymbol, batchSize) { - shell.exec(`${__dirname}/commands/scripts/script.sh Whitelist ${tokenSymbol} ${batchSize} ${remoteNetwork} ${program.remoteNode}`); + shell.exec(`${__dirname}/commands/scripts/script.sh Whitelist ${tokenSymbol} ${batchSize} ${program.remoteNode}`); }); program From e6cff1feafea4384c25f467ae06f4f3955f3e503 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 3 Oct 2018 10:57:26 -0300 Subject: [PATCH 2/6] Fix for POLY transfer out of gas error --- CLI/commands/ST20Generator.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index 1b7fd034b..01c30e2a2 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -350,7 +350,7 @@ async function cappedSTO_launch() { process.exit(0); } else { let transferAction = polyToken.methods.transfer(securityToken._address, new BigNumber(transferAmount)); - let receipt = await common.sendTransaction(Issuer, transferAction, defaultGasPrice, 0, 1.5); + let receipt = await common.sendTransaction(Issuer, transferAction, defaultGasPrice, 0, 2); let event = common.getEventFromLogs(polyToken._jsonInterface, receipt.logs, 'Transfer'); console.log(`Number of POLY sent: ${web3.utils.fromWei(new web3.utils.BN(event._value))}`) } @@ -744,17 +744,17 @@ async function usdTieredSTO_launch() { let stoFee = usdTieredSTOFee; let contractBalance = await polyToken.methods.balanceOf(securityToken._address).call(); let requiredAmount = web3.utils.toWei(stoFee.toString(), "ether"); - if (parseInt(contractBalance) < parseInt(requiredAmount)) { - let transferAmount = parseInt(requiredAmount) - parseInt(contractBalance); - let ownerBalance = await polyToken.methods.balanceOf(Issuer.address).call(); - if(parseInt(ownerBalance) < transferAmount) { + if (new web3.utils.BN(contractBalance).lt(new web3.utils.BN(requiredAmount))) { + let transferAmount = (new web3.utils.BN(requiredAmount)).sub(new web3.utils.BN(contractBalance)); + let ownerBalance = new web3.utils.BN(await polyToken.methods.balanceOf(Issuer.address).call()); + if (ownerBalance.lt(transferAmount)) { console.log(chalk.red(`\n**************************************************************************************************************************************************`)); - console.log(chalk.red(`Not enough balance to pay the ${selectedSTO} fee, Requires ${(new BigNumber(transferAmount).dividedBy(new BigNumber(10).pow(18))).toNumber()} POLY but have ${(new BigNumber(ownerBalance).dividedBy(new BigNumber(10).pow(18))).toNumber()} POLY. Access POLY faucet to get the POLY to complete this txn`)); + console.log(chalk.red(`Not enough balance to pay the ${selectedSTO} fee, Requires ${web3.utils.fromWei(transferAmount)} POLY but have ${web3.utils.fromWei(ownerBalance)} POLY. Access POLY faucet to get the POLY to complete this txn`)); console.log(chalk.red(`**************************************************************************************************************************************************\n`)); process.exit(0); } else { - let transferAction = polyToken.methods.transfer(securityToken._address, new BigNumber(transferAmount)); - let receipt = await common.sendTransaction(Issuer, transferAction, defaultGasPrice, 0, 1.5); + let transferAction = polyToken.methods.transfer(securityToken._address, transferAmount); + let receipt = await common.sendTransaction(Issuer, transferAction, defaultGasPrice, 0, 2); let event = common.getEventFromLogs(polyToken._jsonInterface, receipt.logs, 'Transfer'); console.log(`Number of POLY sent: ${web3.utils.fromWei(new web3.utils.BN(event._value))}`) } From 70a519e72d7c6b2285ede5ed63dd858d9f9a4732 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 3 Oct 2018 13:18:41 -0300 Subject: [PATCH 3/6] CLI fix for scripts on remote nodes --- CLI/commands/ST20Generator.js | 11 +++++++---- CLI/commands/accredit.js | 1 + CLI/commands/changeNonAccreditedLimit.js | 1 + CLI/commands/multi_mint.js | 1 + CLI/commands/scripts/script.sh | 8 ++++---- CLI/commands/whitelist.js | 1 + 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index 01c30e2a2..1afbce936 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -45,11 +45,14 @@ let _tokenConfig; let _mintingConfig; let _stoConfig; +let network; + async function executeApp(tokenConfig, mintingConfig, stoConfig, remoteNetwork) { _tokenConfig = tokenConfig; _mintingConfig = mintingConfig; _stoConfig = stoConfig; + network = remoteNetwork; await global.initialize(remoteNetwork); common.logAsciiBull(); @@ -257,11 +260,11 @@ async function step_Wallet_Issuance(){ async function multi_mint_tokens() { //await whitelist.startWhitelisting(tokenSymbol); - shell.exec(`${__dirname}/scripts/script.sh Whitelist ${tokenSymbol} 75`); + shell.exec(`${__dirname}/scripts/script.sh Whitelist ${tokenSymbol} 75 ${network}`); console.log(chalk.green(`\nCongrats! All the affiliates get succssfully whitelisted, Now its time to Mint the tokens\n`)); console.log(chalk.red(`WARNING: `) + `Please make sure all the addresses that get whitelisted are only eligible to hold or get Security token\n`); - shell.exec(`${__dirname}/scripts//script.sh Multimint ${tokenSymbol} 75`); + shell.exec(`${__dirname}/scripts//script.sh Multimint ${tokenSymbol} 75 ${network}`); console.log(chalk.green(`\nHurray!! Tokens get successfully Minted and transfered to token holders`)); } @@ -1017,7 +1020,7 @@ async function usdTieredSTO_configure() { await common.sendTransaction(Issuer, changeAccreditedAction, defaultGasPrice); break; case 2: - shell.exec(`${__dirname}/scripts/script.sh Accredit ${tokenSymbol} 75`); + shell.exec(`${__dirname}/scripts/script.sh Accredit ${tokenSymbol} 75 ${network}`); break; case 3: let account = readlineSync.question('Enter the address to change non accredited limit: '); @@ -1029,7 +1032,7 @@ async function usdTieredSTO_configure() { await common.sendTransaction(Issuer, changeNonAccreditedLimitAction, defaultGasPrice); break; case 4: - shell.exec(`${__dirname}/scripts/script.sh NonAccreditedLimit ${tokenSymbol} 75`); + shell.exec(`${__dirname}/scripts/script.sh NonAccreditedLimit ${tokenSymbol} 75 ${network}`); break; case 5: await modfifyTimes(); diff --git a/CLI/commands/accredit.js b/CLI/commands/accredit.js index 7f0cc6a75..c4dbd78b6 100644 --- a/CLI/commands/accredit.js +++ b/CLI/commands/accredit.js @@ -33,6 +33,7 @@ let badData = new Array(); startScript(); async function startScript() { + if (remoteNetwork == 'undefined') remoteNetwork = undefined; await global.initialize(remoteNetwork); try { let securityTokenRegistryAddress = await contracts.securityTokenRegistry(); diff --git a/CLI/commands/changeNonAccreditedLimit.js b/CLI/commands/changeNonAccreditedLimit.js index 374093773..b1ececbc7 100644 --- a/CLI/commands/changeNonAccreditedLimit.js +++ b/CLI/commands/changeNonAccreditedLimit.js @@ -33,6 +33,7 @@ let badData = new Array(); startScript(); async function startScript() { + if (remoteNetwork == 'undefined') remoteNetwork = undefined; await global.initialize(remoteNetwork); try { let securityTokenRegistryAddress = await contracts.securityTokenRegistry(); diff --git a/CLI/commands/multi_mint.js b/CLI/commands/multi_mint.js index 908216b58..64745c4b9 100644 --- a/CLI/commands/multi_mint.js +++ b/CLI/commands/multi_mint.js @@ -35,6 +35,7 @@ let badData = new Array(); startScript(); async function startScript() { + if (remoteNetwork == 'undefined') remoteNetwork = undefined; await global.initialize(remoteNetwork); try { diff --git a/CLI/commands/scripts/script.sh b/CLI/commands/scripts/script.sh index 1a88207fe..2ee363a8f 100755 --- a/CLI/commands/scripts/script.sh +++ b/CLI/commands/scripts/script.sh @@ -3,17 +3,17 @@ if [ $1 = "Whitelist" ]; then echo "Running the $1 script"; -node $PWD/CLI/commands/whitelist.js $2 $3 +node $PWD/CLI/commands/whitelist.js $2 $3 $4 elif [ $1 = "Multimint" ]; then echo "Running the $1 script"; -node $PWD/CLI/commands/multi_mint.js $2 $3 +node $PWD/CLI/commands/multi_mint.js $2 $3 $4 elif [ $1 = "Accredit" ]; then echo "Running the $1 script"; -node $PWD/CLI/commands/accredit.js $2 $3 +node $PWD/CLI/commands/accredit.js $2 $3 $4 elif [ $1 = "NonAccreditedLimit" ]; then echo "Running the $1 script"; -node $PWD/CLI/commands/changeNonAccreditedLimit.js $2 $3 +node $PWD/CLI/commands/changeNonAccreditedLimit.js $2 $3 $4 fi diff --git a/CLI/commands/whitelist.js b/CLI/commands/whitelist.js index 903ef40ec..4750adffa 100644 --- a/CLI/commands/whitelist.js +++ b/CLI/commands/whitelist.js @@ -32,6 +32,7 @@ const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); startScript(); async function startScript() { + if (remoteNetwork == 'undefined') remoteNetwork = undefined; await global.initialize(remoteNetwork); try { From acd376d1bb4f1eb5e171beb8c9afc32f0f853267 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 10 Oct 2018 09:49:26 -0300 Subject: [PATCH 4/6] CLI: Allow any combination of raise types for USDTieredSTO --- CLI/commands/ST20Generator.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/CLI/commands/ST20Generator.js b/CLI/commands/ST20Generator.js index 1afbce936..90d2d4649 100644 --- a/CLI/commands/ST20Generator.js +++ b/CLI/commands/ST20Generator.js @@ -521,19 +521,20 @@ function fundingConfigUSDTieredSTO() { if (typeof _stoConfig !== 'undefined' && _stoConfig.hasOwnProperty('fundingType')) { selectedFunding = _stoConfig.fundingType; } else { - selectedFunding = readlineSync.question('Enter' + chalk.green(` P `) + 'for POLY raise,' + chalk.green(` D `) + 'for DAI raise,' + chalk.green(` E `) + 'for Ether raise or' + chalk.green(` A `) + 'for all (A): ').toUpperCase(); + selectedFunding = readlineSync.question('Enter' + chalk.green(` P `) + 'for POLY raise,' + chalk.green(` D `) + 'for DAI raise,' + chalk.green(` E `) + 'for Ether raise or any combination of them (i.e.'+ chalk.green(` PED `) + 'for all): ').toUpperCase(); } - if (selectedFunding == 'E') { - funding.raiseType = [FUND_RAISE_TYPES.ETH]; + funding.raiseType = []; + if (selectedFunding.includes('E')) { + funding.raiseType.push(FUND_RAISE_TYPES.ETH); } - else if (selectedFunding == 'P') { - funding.raiseType = [FUND_RAISE_TYPES.POLY]; + if (selectedFunding.includes('P')) { + funding.raiseType.push(FUND_RAISE_TYPES.POLY); } - else if (selectedFunding == 'D') { - funding.raiseType = [FUND_RAISE_TYPES.DAI]; + if (selectedFunding.includes('D')) { + funding.raiseType.push(FUND_RAISE_TYPES.DAI); } - else { + if (funding.raiseType.length == 0) { funding.raiseType = [FUND_RAISE_TYPES.ETH, FUND_RAISE_TYPES.POLY, FUND_RAISE_TYPES.DAI]; } From 37ec6e60f639e6261cf436c0893fb856652b425a Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 10 Oct 2018 11:45:47 -0300 Subject: [PATCH 5/6] Remove CLI restriction to mint tokens if STO is attached --- CLI/commands/dividends_manager.js | 25 ++++++++++--------------- CLI/commands/module_manager.js | 5 ----- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/CLI/commands/dividends_manager.js b/CLI/commands/dividends_manager.js index a757b78ef..c4f158cd6 100644 --- a/CLI/commands/dividends_manager.js +++ b/CLI/commands/dividends_manager.js @@ -194,24 +194,19 @@ async function mintTokens(address, amount){ if (await securityToken.methods.mintingFrozen().call()) { console.log(chalk.red("Minting is not possible - Minting has been permanently frozen by issuer")); } else { - let result = await securityToken.methods.getModulesByType(MODULES_TYPES.STO).call(); - if (result.length > 0) { - console.log(chalk.red("Minting is not possible - STO is attached to Security Token")); - } else { - await whitelistAddress(address); + await whitelistAddress(address); - try { - let mintAction = securityToken.methods.mint(address,web3.utils.toWei(amount)); - let receipt = await common.sendTransaction(Issuer, mintAction, defaultGasPrice); - let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'Transfer'); - console.log(` + try { + let mintAction = securityToken.methods.mint(address,web3.utils.toWei(amount)); + let receipt = await common.sendTransaction(Issuer, mintAction, defaultGasPrice); + let event = common.getEventFromLogs(securityToken._jsonInterface, receipt.logs, 'Transfer'); + console.log(` Minted ${web3.utils.fromWei(event.value)} tokens to account ${event.to}` - ); - } catch (err) { - console.log(err); - console.log(chalk.red("There was an error processing the transfer transaction. \n The most probable cause for this error is one of the involved accounts not being in the whitelist or under a lockup period.")); - } + ); + } catch (err) { + console.log(err); + console.log(chalk.red("There was an error processing the transfer transaction. \n The most probable cause for this error is one of the involved accounts not being in the whitelist or under a lockup period.")); } } } diff --git a/CLI/commands/module_manager.js b/CLI/commands/module_manager.js index b351a475d..2360e39dc 100644 --- a/CLI/commands/module_manager.js +++ b/CLI/commands/module_manager.js @@ -385,11 +385,6 @@ async function mintTokens() { console.log(chalk.red("Minting is not possible - Minting has been permanently frozen by issuer")); return; } - let stoModules = await securityToken.methods.getModulesByType(STO_KEY).call(); - if (stoModules.length > 0) { - console.log(chalk.red("Minting is not possible - STO is attached to Security Token")); - return; - } let _investor = readlineSync.question(chalk.yellow(`Enter the address to receive the tokens: `)); let _amount = readlineSync.question(chalk.yellow(`Enter the amount of tokens to mint: `)); From 92f81ddfb9f7c7bc02eb5b24854bfd2e9f143576 Mon Sep 17 00:00:00 2001 From: Victor Vicente Date: Wed, 10 Oct 2018 15:19:28 -0300 Subject: [PATCH 6/6] KYC expiry verification --- CLI/commands/investor_portal.js | 16 +++++++++--- CLI/commands/multi_mint.js | 45 +++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/CLI/commands/investor_portal.js b/CLI/commands/investor_portal.js index e08378fd9..fd308138d 100644 --- a/CLI/commands/investor_portal.js +++ b/CLI/commands/investor_portal.js @@ -36,6 +36,7 @@ let STOAddress; // Global display variables let displayCanBuy; +let displayValidKYC; // Start Script async function executeApp(investorAddress, investorPrivKey, symbol, currency, amount, remoteNetwork) { @@ -192,14 +193,15 @@ async function showCappedSTOInfo() { } } + let now = Math.floor(Date.now()/1000); + await generalTransferManager.methods.whitelist(User.address).call({}, function(error, result){ displayCanBuy = result.canBuyFromSTO; + displayValidKYC = parseInt(result.expiryTime) > now; }); - let now = Math.floor(Date.now()/1000); let timeTitle; let timeRemaining; - if(now < displayStartTime){ timeTitle = "STO starts in: "; timeRemaining = displayStartTime - now; @@ -229,6 +231,9 @@ async function showCappedSTOInfo() { if(!displayCanBuy) { console.log(chalk.red(`Your address is not approved to participate in this token sale.\n`)); process.exit(0); + } else if (!displayValidKYC) { + console.log(chalk.red(`Your KYC is expired.\n`)); + process.exit(0); } else if (now < displayStartTime) { console.log(chalk.red(`The token sale has not yet started.\n`)); process.exit(0); @@ -252,8 +257,10 @@ async function showUserInfoForUSDTieredSTO() await generalTransferManager.methods.whitelist(User.address).call({}, function(error, result){ displayCanBuy = result.canBuyFromSTO; + displayValidKYC = parseInt(result.expiryTime) > Math.floor(Date.now()/1000); }); - console.log(` - Whitelisted: ${(displayCanBuy)? 'YES' : 'NO'}`) + console.log(` - Whitelisted: ${(displayCanBuy)? 'YES' : 'NO'}`); + console.log(` - Valid KYC: ${(displayValidKYC)? 'YES' : 'NO'}`); let displayIsUserAccredited = await currentSTO.methods.accredited(User.address).call(); console.log(` - Accredited: ${(displayIsUserAccredited)? "YES" : "NO"}`) @@ -382,6 +389,9 @@ async function showUSDTieredSTOInfo() { if (!displayCanBuy) { console.log(chalk.red(`Your address is not approved to participate in this token sale.\n`)); process.exit(0); + } else if (!displayValidKYC) { + console.log(chalk.red(`Your KYC is expired.\n`)); + process.exit(0); } else if (now < displayStartTime) { console.log(chalk.red(`The token sale has not yet started.\n`)); process.exit(0); diff --git a/CLI/commands/multi_mint.js b/CLI/commands/multi_mint.js index 64745c4b9..0b7c272ca 100644 --- a/CLI/commands/multi_mint.js +++ b/CLI/commands/multi_mint.js @@ -134,6 +134,7 @@ function readFile() { `); let affiliatesFailedArray = []; + let affiliatesKYCInvalidArray = []; //this for loop will do the batches, so it should run 75, 75, 50 with 200 for (let i = 0; i < distribData.length; i++) { try { @@ -143,12 +144,20 @@ function readFile() { for (let j = 0; j < distribData[i].length; j++) { let investorAccount = distribData[i][j][0]; let tokenAmount = web3.utils.toWei((distribData[i][j][1]).toString(),"ether"); - let verifiedTransaction = await securityToken.methods.verifyTransfer("0x0000000000000000000000000000000000000000", investorAccount, tokenAmount).call(); + let verifiedTransaction = await securityToken.methods.verifyTransfer("0x0000000000000000000000000000000000000000", investorAccount, tokenAmount, web3.utils.fromAscii('')).call(); if (verifiedTransaction) { affiliatesVerifiedArray.push(investorAccount); tokensVerifiedArray.push(tokenAmount); } else { - affiliatesFailedArray.push(investorAccount); + let gtmModule = await securityToken.methods.getModulesByName(web3.utils.toHex('GeneralTransferManager')).call(); + let generalTransferManagerABI = abis.generalTransferManager(); + let generalTransferManager = new web3.eth.Contract(generalTransferManagerABI, gtmModule[0]); + let validKYC = (await generalTransferManager.methods.whitelist(Issuer.address).call()).expiryTime > Math.floor(Date.now()/1000); + if (validKYC) { + affiliatesFailedArray.push(investorAccount); + } else { + affiliatesKYCInvalidArray.push(investorAccount); + } } } let mintMultiAction = securityToken.methods.mintMulti(affiliatesVerifiedArray, tokensVerifiedArray); @@ -182,8 +191,8 @@ function readFile() { for (var i = 0; i < event_data.length; i++) { let combineArray = []; - let investorAddress_Event = event_data[i].returnValues.to; - let amount_Event = event_data[i].returnValues.amount; + let investorAddress_Event = event_data[i].returnValues._to; + let amount_Event = event_data[i].returnValues._value; let blockNumber = event_data[i].blockNumber combineArray.push(investorAddress_Event); @@ -214,9 +223,10 @@ function readFile() { console.log(`******************** EVENT LOGS ANALYSIS COMPLETE ********************\n`); console.log(`A total of ${totalInvestors} affiliated investors get the token\n`); - console.log(`This script in total sent ${fullFileData.length - badData.length - affiliatesFailedArray.length} new investors and updated investors to the blockchain.\n`); + console.log(`This script in total sent ${fullFileData.length - badData.length - affiliatesFailedArray.length - affiliatesKYCInvalidArray.length} new investors and updated investors to the blockchain.\n`); console.log(`There were ${badData.length} bad entries that didnt get sent to the blockchain in the script.\n`); - console.log(`There were ${affiliatesFailedArray.length} accounts that didnt get sent to the blockchain as they would fail.\n`); + console.log(`There were ${affiliatesKYCInvalidArray.length} accounts with invalid KYC.\n`); + console.log(`There were ${affiliatesFailedArray.length} accounts that didn't get sent to the blockchain as they would fail.\n`); console.log("************************************************************************************************"); console.log("OBJECT WITH EVERY USER AND THEIR MINTED TOKEN: \n\n", investorObjectLookup) @@ -225,27 +235,36 @@ function readFile() { let missingDistribs = []; let failedVerificationDistribs = []; + let invalidKYCDistribs = []; for (let l = 0; l < fullFileData.length; l++) { - if (affiliatesFailedArray.includes(fullFileData[l][0])) { + if (affiliatesKYCInvalidArray.includes(fullFileData[l][0])) { + invalidKYCDistribs.push(fullFileData[l]); + } else if (affiliatesFailedArray.includes(fullFileData[l][0])) { failedVerificationDistribs.push(fullFileData[l]); } else if (!investorObjectLookup.hasOwnProperty(fullFileData[l][0])) { missingDistribs.push(fullFileData[l]); } } + if (invalidKYCDistribs.length > 0) { + console.log("**************************************************************************************************************************"); + console.log("The following data arrays have an invalid KYC. Please review if these accounts are whitelisted and their KYC is not expired\n"); + console.log(invalidKYCDistribs); + console.log("**************************************************************************************************************************"); + } if (failedVerificationDistribs.length > 0) { - console.log("************************************************************************************************"); + console.log("*********************************************************************************************************"); console.log("-- The following data arrays failed at verifyTransfer. Please review if these accounts are whitelisted --\n"); console.log(failedVerificationDistribs); - console.log("************************************************************************************************"); + console.log("*********************************************************************************************************"); } if (missingDistribs.length > 0) { - console.log("************************************************************************************************"); - console.log("-- No Minted event was found for the following data arrays. Please review them manually --"); + console.log("******************************************************************************************"); + console.log("-- No Minted event was found for the following data arrays. Please review them manually --\n"); console.log(missingDistribs); - console.log("************************************************************************************************"); + console.log("******************************************************************************************"); } - if (missingDistribs.length == 0 && failedVerificationDistribs.length == 0) { + if (missingDistribs.length == 0 && failedVerificationDistribs.length == 0 && invalidKYCDistribs.length == 0) { console.log("\n**************************************************************************************************************************"); console.log("All accounts passed through from the CSV were successfully get the tokens, because we were able to read them all from events"); console.log("****************************************************************************************************************************");