diff --git a/.circleci/config.yml b/.circleci/config.yml index 2f8945d91..efdf87dd2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,7 +45,7 @@ jobs: - run: yarn install - run: node --version - run: truffle version - - run: + - run: command: npm run coverage no_output_timeout: 1h - save_cache: @@ -65,6 +65,7 @@ jobs: - run: node --version - run: truffle version - run: npm run clash-check + - run: npm run istr-check - save_cache: key: dependency-cache-{{ checksum "package.json" }} paths: diff --git a/package.json b/package.json index 8221b6035..fe7227dcb 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "test": "scripts/test.sh 2> /dev/null", "clash-check": "node scripts/clashCheck.js", + "istr-check": "node scripts/ISTRCheck.js", "gas": "scripts/gasUsage.sh", "wintest": "scripts\\wintest.cmd", "wincov": "scripts\\wincov.cmd", diff --git a/scripts/ISTRCheck.js b/scripts/ISTRCheck.js new file mode 100644 index 000000000..9bbaf7f64 --- /dev/null +++ b/scripts/ISTRCheck.js @@ -0,0 +1,118 @@ +const fs = require('fs'); +const exec = require('child_process').execSync; +const chalk = require('chalk'); + +// These functions/events are allowed to differ. (These are present in STR but not used and hence not defined in ISTR) +let exceptions = [ + "getBytes32Value", + "getBytesValue", + "getAddressValue", + "getArrayAddress", + "getBoolValue", + "getStringValue", + "getArrayBytes32", + "getUintValue", + "getArrayUint", + "initialize", + "getBytes32Value", + "getBytesValue", + "getAddressValue", + "getArrayAddress", + "getBoolValue", + "getStringValue", + "getArrayBytes32", + "getUintValue", + "getArrayUint", + undefined, // constructor +]; + +async function readFiles() { + if (!fs.existsSync("./build/contracts/ISecurityTokenRegistry.json")) { + console.log(chalk.yellow('Compiling contracts. This may take a while, please wait.')); + exec('./node_modules/.bin/truffle compile'); + } + return([ + JSON.parse(fs.readFileSync(`./build/contracts/ISecurityTokenRegistry.json`).toString()).abi, + [ + ...JSON.parse(fs.readFileSync(`./build/contracts/SecurityTokenRegistry.json`).toString()).abi, + ...JSON.parse(fs.readFileSync(`./build/contracts/STRGetter.json`).toString()).abi + ] + ]); +} + +async function checkISTR() { + // Reading ABIs from build files + let ABIs = await readFiles(); + + // Removing functions/events defined in exceptions array. + removeExceptions(ABIs); + + // Removing parameter and return names from ABIs as they can differ. + // Only cleaning ABIs of second file as first one can be cleaned in the next loop efficiently. + for (let i = 0; i < ABIs[1].length; i++) { + cleanABI(ABIs[1][i]); + } + + // This function removed duplicate elements from the ABI. + // i.e If the signature matches in Interface and the contract, it is removed from the ABI. + // This means that the left over elements after this loop are mistakes. + for (let i = 0; i < ABIs[0].length; i++) { + let fna = cleanABI(ABIs[0][i]); + for (let j = 0; j < ABIs[1].length; j++) { + let fnb = ABIs[1][j]; + if (fna.name == fnb.name && fna.type == fnb.type) { + if (JSON.stringify(fna) === JSON.stringify(fnb)) { + ABIs[0].splice(i, 1); + ABIs[1].splice(j, 1); + i--; + break; + } + } + } + } + + // If there is any element remaining in either ABI, it is an error. + if (ABIs[0].length >= 1 || ABIs[1].length > 1) { + for (let i = 0; i < ABIs[0].length; i++) { + console.log(ABIs[0][i].name); + } + for (let i = 0; i < ABIs[1].length; i++) { + console.log(ABIs[1][i].name); + } + console.log(chalk.red('The above Functions/events had no match found. Please synchronize the Interface with the contract.')); + process.exit(1); + } +} + +function cleanABI(element) { + if (element.type === 'event') { + for(let i = 0; i < element.inputs.length; i++) { + element.inputs[i].name = ""; + } + } else if (element.type === 'function') { + for(let i = 0; i < element.inputs.length; i++) { + element.inputs[i].name = ""; + } + for(let i = 0; i < element.outputs.length; i++) { + element.outputs[i].name = ""; + } + } + return element; +} + +function removeExceptions(ABIs) { + for (let i = 0; i < ABIs[0].length; i++) { + if (exceptions.includes(ABIs[0][i].name)) { + ABIs[0].splice(i, 1); + i--; + } + } + for (let i = 0; i < ABIs[1].length; i++) { + if (exceptions.includes(ABIs[1][i].name)) { + ABIs[1].splice(i, 1); + i--; + } + } +} + +checkISTR(); diff --git a/scripts/calculateSize.js b/scripts/calculateSize.js index 3f3db87f9..88d1e1d4c 100644 --- a/scripts/calculateSize.js +++ b/scripts/calculateSize.js @@ -9,7 +9,7 @@ async function readFiles() { return fs.readdirSync("./build/contracts/"); } else { console.log('Compiling contracts. This may take a while, please wait.'); - exec('truffle compile'); + exec('./node_modules/.bin/truffle compile'); return fs.readdirSync("./build/contracts/"); } } diff --git a/scripts/clashCheck.js b/scripts/clashCheck.js index 09f36d31c..6133d4c0b 100644 --- a/scripts/clashCheck.js +++ b/scripts/clashCheck.js @@ -8,7 +8,7 @@ async function readFiles() { return fs.readdirSync("./build/contracts/"); } else { console.log(chalk.yellow('Compiling contracts. This may take a while, please wait.')); - exec('truffle compile'); + exec('./node_modules/.bin/truffle compile'); return fs.readdirSync("./build/contracts/"); } } @@ -47,9 +47,10 @@ async function checkClashes() { }); if (clashesFound) { console.log(chalk.yellow("The clash(es) might be in two different contracts and hence not be am Issue.\nThis script can not detect this (yet) because of proxy contracts")); - throw("Clash(es) found! Please fix."); - } + console.log(chalk.red("Clash(es) found! Please fix.")); + process.exit(1); + } console.log(chalk.green("Clash check finished. No Clashes found.")); } -checkClashes(); \ No newline at end of file +checkClashes();