diff --git a/addressbook/index.js b/addressbook/index.js new file mode 100644 index 0000000..adce199 --- /dev/null +++ b/addressbook/index.js @@ -0,0 +1,39 @@ +var jsonfile = require('jsonfile'); + +module.exports = { + get: function() { + return jsonfile.readFileSync(process.cwd() + '/addressbook.json'); + }, + add: function(contracts) { + if(contracts[Object.keys(contracts)[0]].currentProvider.ganache === undefined) { + const assign = require('assign-deep'); + for (var contract in contracts) { + var host = contracts[contract].currentProvider.host + var network = /(?<=https:\/\/).*?(?=.infura.io)/.exec(host) + const file = process.cwd() + '/addressbook.json'; + var book = jsonfile.readFileSync(file) + if(network === null){ + var obj = { + [host]:{ + [contract]:contracts[contract].options.address + } + } + }else { + var obj = { + [network]:{ + [contract]:contracts[contract].options.address + } + } + var result = assign(book, obj) } + jsonfile.writeFileSync(file, result, { spaces:2 }) + } + } + }, + checkNetwork: function(network) { + var book = require(process.cwd()+'/addressbook.json'); + if(typeof book[network] === "undefined") { + console.log(("There are no contracts registered for this network in your address book. Please make sure you deploy your contracts to " + network + " first").red) + process.exit() + } + } +} \ No newline at end of file diff --git a/docs.js b/docs/index.js similarity index 100% rename from docs.js rename to docs/index.js diff --git a/template.js b/docs/template.js similarity index 100% rename from template.js rename to docs/template.js diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index 63fb2a2..0000000 --- a/example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -secrets.json \ No newline at end of file diff --git a/example/addressbook.json b/example/addressbook.json deleted file mode 100644 index 9e26dfe..0000000 --- a/example/addressbook.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/example/contracts/Token.sol b/example/contracts/Token.sol deleted file mode 100644 index 5f9559c..0000000 --- a/example/contracts/Token.sol +++ /dev/null @@ -1,38 +0,0 @@ -pragma solidity ^0.4.24; - -/// @title A very minimal token contract -contract Token { - - uint256 public totalSupply = 1*10**28; - string public name = "Token"; - uint8 public decimals = 18; - string public symbol = "TOK"; - mapping (address => uint256) balances; - event Transfer(address indexed _from, address indexed _to, uint256 _value); - - constructor() public { - balances[msg.sender] = totalSupply; - } - - /// @author Nour Haridy - /// @dev Transfers tokens - /// @param _to The address of the transfer recipient - /// @param _value The amount of tokens to be transferred - /// @return true if tokens transferred successfully - function transfer(address _to, uint256 _value) public returns (bool success) { - require(balances[msg.sender] >= _value); - balances[msg.sender] -= _value; - balances[_to] += _value; - emit Transfer(msg.sender, _to, _value); - return true; - } - - /// @author Nour Haridy - /// @dev Checks balance of address - /// @param _owner The queried address - /// @return balance of address - function balanceOf(address _owner) constant public returns (uint256 balance) { - return balances[_owner]; - } - -} \ No newline at end of file diff --git a/example/docs/README.md b/example/docs/README.md deleted file mode 100644 index da9a604..0000000 --- a/example/docs/README.md +++ /dev/null @@ -1 +0,0 @@ -# Smart Contract Documentation diff --git a/example/parasol.js b/example/parasol.js deleted file mode 100644 index 2ec3fad..0000000 --- a/example/parasol.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = { - dev: { // Ganache-cli options (https://github.com/trufflesuite/ganache-cli) - port:8555, - total_accounts:10, - locked:false, - debug:false, - //logger:console, - gasPrice: 0 - }, - contracts : "*", // To select specific contracts, replace it with an array: ["File1.sol", "Folder/File2.sol"] - solc: { // Solidity compiler options (https://solidity.readthedocs.io/en/develop/using-the-compiler.html) - optimizer: { - enabled: true, - // Optimize for how many times you intend to run the code. - // Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage. - runs: 200 - }, - evmVersion: "byzantium", // Version of the EVM to compile for. Affects type checking and code generation. Can be homestead, tangerineWhistle, spuriousDragon, byzantium or constantinople - // UNCOMMENT IF USING LIBRARIES: Addresses of the libraries. If not all libraries are given here, it can result in unlinked objects whose output data is different. - // libraries: { - // // The top level key is the the name of the source file where the library is used. - // // If remappings are used, this source file should match the global path after remappings were applied. - // // If this key is an empty string, that refers to a global level. - // "myFile.sol": { - // "MyLib": "0x123123..." - // } - // }, - outputSelection: { - "*": { - "*": [ "metadata", "evm.bytecode", "devdoc" ] - } - } - }, - deployer: async function (contracts, network, web3, test, save) { - for (var contract in contracts) { - var gasPrice = "50000000000"; //50 Gwei - if(network === "dev") { - gasPrice = "0"; - } - contracts[contract] = await contracts[contract].deploy().send({from: web3.eth.accounts[0], gasPrice, gas:1000000}) - console.log(contract + " deployed at address " + contracts[contract].options.address) - } - save(contracts) // Saves contract addresses to addressbook.json. Development addresses will never be saved to addressbook. - test(contracts) // Call the test function if you want to run unit tests after deployment. Tests will only run if network is dev - } -} \ No newline at end of file diff --git a/example/tests/Token.js b/example/tests/Token.js deleted file mode 100644 index 8f067f6..0000000 --- a/example/tests/Token.js +++ /dev/null @@ -1,7 +0,0 @@ -describe('Token.sol', function() { - describe('Transfer()', function() { - it('should revert when transferred amount is smaller than 0', function() { - contracts['Token.sol:Token'].methods.transfer(address0, -1).send().on('error', (e) => assertRevert(e)) - }); - }); -}); \ No newline at end of file diff --git a/hooks/index.js b/hooks/index.js new file mode 100644 index 0000000..b7fcbe0 --- /dev/null +++ b/hooks/index.js @@ -0,0 +1,77 @@ +module.exports = { + onCompiled: function (context, callback) { + if(typeof this.compiled[context.source] === "array") { + this.compiled[context.source].push(callback); + } else { + this.compiled[context.source] = [callback]; + } + }, + compiled: {}, + executeCompiled(compiledFileName) { + for (fileName in this.compiled) { + if (compiledFileName.startsWith(fileName)) { + for (var i = 0; i < this.compiled[fileName].length; i++) { + this.compiled[fileName][i](compiledFileName) + } + } + } + }, + onDeployed: function (context, callback) { + if(typeof this.deployed[context.source] === "array") { + this.deployed[context.source].push(callback); + } else { + this.deployed[context.source] = [callback]; + } + }, + deployed: {}, + executeDeployed(contracts) { + this.executeAllDeployed(contracts) + for (contractName in contracts) { + for (fileName in this.deployed) { + if (contractName.startsWith(fileName)) { + for (var i = 0; i < this.deployed[fileName].length; i++) { + this.deployed[fileName][i](contracts[contractName], contractName) + } + + } + } + } + }, + onAllDeployed: function (callback) { + this.allDeployed.push(callback) + }, + allDeployed: [], + executeAllDeployed: function(contracts){ + for (var i = 0; i < this.allDeployed.length; i++) { + this.allDeployed[i](contracts) + } + }, + onError: function (context, callback) { + if(typeof this.errors[context.source] === "array") { + this.errors[context.source].push(callback); + } else { + this.errors[context.source] = [callback]; + } + }, + errors: {}, + executeErrors: function(errors) { + var self = this; + errors.forEach(function(error) { + for (fileName in self.errors) { + if (error.includes(fileName)) { + for (var i = 0; i < self.errors[fileName].length; i++) { + self.errors[fileName][i](error) + } + } + } + }) + }, + tests:{}, + onTest: function (context, description, callback) { + if(typeof this.tests[context.source] != "object") { + this.tests[context.source] = {[description]: callback} + } else { + this.tests[context.source][description] = callback + } + }, +} \ No newline at end of file diff --git a/index.js b/index.js index 5971ab6..bcdced1 100755 --- a/index.js +++ b/index.js @@ -7,14 +7,19 @@ var fse = require('fs-extra') var ganache = require("ganache-cli"); var solc = require('solc'); var read = require('fs-readdir-recursive') -var docs = require('./docs.js') +var docs = require('./docs') +var addressbook = require('./addressbook') +var literals = require('./literals') var Web3 = require('web3'); var rimraf = require('rimraf'); var path = require('path'); var colors = require('colors'); var repl = require('repl'); var stubber = require('async-repl/stubber'); -var jsonfile = require('jsonfile') +var psol = require('psol') +var logger = require('./logger'); +const resnap = require('resnap')() + if(fs.existsSync("./parasol.js")){ var config = require(process.cwd()+'/parasol.js'); } @@ -32,7 +37,7 @@ program var compile = async function(web3, accounts, network) { - delete require.cache[process.cwd()+'/parasol.js']; + resnap(); var config = require(process.cwd()+'/parasol.js'); var networklist = ['mainnet', 'ropsten', 'infuranet', 'kovan', 'rinkeby'] if((networklist.indexOf(network) > -1)) { @@ -58,35 +63,84 @@ program var sources = {} for (var i = 0; i < contracts.length; i++) { if(sources[contracts[i]] != null) { - console.log(("Error: Duplicated file name found: " + contracts[i]).red) + logger.warning("Warning: Duplicated file name found: " + contracts[i]) // Is this necessary? } else { - console.log(('Compiling ' + contracts[i]).blue) sources[contracts[i]] = fs.readFileSync(process.cwd() + '/contracts/' + contracts[i], 'utf8'); } } - var output = solc.compile({ sources, settings:config.solc }, 1) var abort = false; + var context = { + ignored: [], + ignore: function (self) { + this.ignored.push(self.source); + }, + aborted: false, + abortReason:"unknown", + abort: function(reason) { + abort = true; + this.aborted = true; + if(typeof reason === "string") { + this.abortReason = reason; + } + }, + strict: config.preprocessor.strict, + parasol: require('./hooks'), + test: function (context, description, statement) { + if(this.network === "dev") { + this.parasol.onTest(context, description, statement); + } + }, + assertRevert: function(e) { + global.assert(e.results[Object.keys(e.results)[0]].error, 'revert') + }, + web3, + accounts, + network + } + psol(sources, context, config.preprocessor) + + for (var i = 0; i < context.ignored.length; i++) { + for (source in sources) { + if (source.startsWith(context.ignored[i])) { + logger.warn('Preprocessor ignoring compilation of ' + source) + delete sources[source]; + } + } + } + + var output = solc.compile({ sources: sources, settings:config.solc }, 1) + // Print errors var errors = output.errors; if(errors != null) { + if(context.strict || config.preprocessor.strict) { + abort = true; + } for (var i = 0; i < errors.length; i++) { if (errors[i].includes("Error")) { abort = true; - console.log(errors[i].red) + context.parasol.executeErrors(errors) + logger.error(errors[i]) } else { - console.log(errors[i].yellow) + logger.warning(errors[i]) } } } if(abort) { - console.log("Errors have been found while compiling contracts. Aborting.".red) + if(context.aborted) { + logger.error('Deployment aborted by preprocessor. Abort reason: ' + context.abortReason) + } else if(context.strict) { + logger.error('Strict mode is active. Deployment will abort due to errors or warnings') + } else { + logger.error("Errors have been found while compiling contracts. Aborting.") + } }else{ rimraf.sync(process.cwd() + '/ABI/*'); var contractDocs = []; var instances = {} for (var contractName in output.contracts) { + logger.success('Compiled ' + contractName) if(output.contracts[contractName].metadata.length > 0){ //Skip interface contracts - console.log(("Deploying " + contractName).blue); var metadata = JSON.parse(output.contracts[contractName].metadata) var cDocs = metadata; metadata.contractName = contractName; @@ -97,6 +151,7 @@ program instances[contractName] = instance; var filename = contractName.replace(".","_").replace(":","-") + '.json'; fse.outputFileSync(process.cwd() + '/ABI/' + filename,JSON.stringify(ABI, null, 2),{encoding:'utf8',flag:'w'}); + context.parasol.executeCompiled(contractName); } } if(network === "dev" && (program.dev || !process.argv.slice(2).length)) { @@ -107,12 +162,24 @@ program var Mocha = require('mocha'); var mocha = new Mocha(); var testDir = process.cwd() + '/tests' - // Add each .js file to th e mocha instance + // Add each .js file to the mocha instance var files = fs.readdirSync(testDir).filter(function(file){ // Only keep the .js files return file.substr(-3) === '.js'; }) + + if(Object.keys(context.parasol.tests).length > 0) { + for (file in context.parasol.tests) { + var suite = Mocha.Suite.create(mocha.suite, file + ": Inline tests"); + for (test in context.parasol.tests[file]) { + suite.addTest(new Mocha.Test(test, context.parasol.tests[file][test])) + } + //var runner = new Mocha.Runner(suite); + //runner.run(); + } + } + for (var i = 0; i < files.length; i++) { delete require.cache[require.resolve(path.join(testDir, files[i]))] mocha.addFile(path.join(testDir, files[i])) @@ -136,67 +203,24 @@ program } }, function(contracts){ - if(contracts[Object.keys(contracts)[0]].currentProvider.ganache === undefined) { - const assign = require('assign-deep'); - for (var contract in contracts) { - var host = contracts[contract].currentProvider.host - var network = /(?<=https:\/\/).*?(?=.infura.io)/.exec(host) - const file = process.cwd() + '/addressbook.json'; - var addressbook = jsonfile.readFileSync(file) - if(network === null){ - var obj = { - [host]:{ - [contract]:contracts[contract].options.address - } - } - }else { - var obj = { - [network]:{ - [contract]:contracts[contract].options.address - } - } - var result = assign(addressbook, obj) } - jsonfile.writeFileSync(file, result, { spaces:2 }) - } - } + context.parasol.executeDeployed(contracts) + addressbook.add(contracts); }); docs(contractDocs) } } -if (program.dev || !process.argv.slice(2).length) { +if (program.dev || !process.argv.slice(2).length) { // Default argument if (fs.existsSync("./parasol.js")) { var provider = ganache.provider(config.dev) provider.ganache = true; var web3 = new Web3(provider); - console.log(('Ethereum development network running on port ' + config.dev.port).blue) + logger.success('Ethereum development network running on port ' + config.dev.port) web3.eth.getAccounts().then(function(accounts){ replInstance = repl.start({ prompt: 'parasol> '.bold.cyan, useGlobal:true, ignoreUndefined:true, useColors:true }); replInstance.defineCommand('help', { action: function(){ - console.log(` -Parasol global variables: - web3 web3 1.0 already attached to the Ganache provider and 10 generated accounts funded with 100 ETH each - contracts Object of contract instances deployed on ganache. Key is relative location from contracts/ folder + ":" + contract name - address0 Short for 0x00000000000000000000000000000000000 also known as address(0) in solidity. Useful to reduce code redundancy - accounts Array of public Ethereum addresses of accounts attached to the above web3 instance - assert The native Node.js assertion module required for basic unit tests - assertRevert Special assertion function used to assert failure of a web3 send transaction. Takes a Promise error as an argument. -Parasol commands: - .recompile Recompile all contracts, redeploy on devnet, recompile docs & run tests - .deploy .deploy [network] will deploy contracts to [network] (Default network is mainnet) -REPL commands: - .break Sometimes you get stuck, this gets you out - .clear Alias for .break - .editor Enter editor mode - .exit Exit the repl - .help Print this help message - .history Show the history - .load Load JS from a file into the REPL session - .save Save all evaluated commands in this REPL session to a file -Documentation: - https://developer.lamarkaz.com/parasol - `) + console.log(literals.dev) replInstance.displayPrompt() } }) @@ -207,39 +231,38 @@ Documentation: }) replInstance.defineCommand('deploy', { action: function(network){ - console.log(network) deploy(network) } }) replInstance.on('exit', () => { - console.log('Shutting down Parasol development environment'.blue); + logger.info('Shutting down Parasol development environment'.blue); watcher.close(); process.exit(); }); stubber(replInstance); compile(web3, accounts, "dev"); global.watcher = watch('./', { recursive: true }, function(evt, name) { - if((name.endsWith('.json') || name.endsWith('.js') || name.endsWith('.sol')) && !name.startsWith('ABI/')) { - console.log('%s changed. Recompiling.'.blue, name); + if((name.endsWith('.json') || name.endsWith('.js') || name.endsWith('.sol') || name.endsWith('.psol')) && !name.startsWith('ABI/')) { + logger.info(name + ' changed. Recompiling.'); compile(web3, accounts, "dev") replInstance.displayPrompt() } }); }) } else { - console.log('This is not a valid Parasol project. Please run "parasol init" in an empty directory to initialize a new project.'.red) + logger.error('This is not a valid Parasol project. Please run "parasol init" in an empty directory to initialize a new project.') } } if (program.init) { if(fs.existsSync("./parasol.js")){ - console.log('This directory already contains a Parasol project'.red) + logger.error('This directory already contains a Parasol project') } else { try { fse.copySync(__dirname + '/init/', './') - console.log('Parasol project created successfully!'.green) + logger.success('Parasol project created successfully!') } catch (err) { - console.error(err.red) + logger.error(err) } } } @@ -249,12 +272,12 @@ if(program.test) { var provider = ganache.provider(config.dev) provider.ganache = true; var web3 = new Web3(provider); - console.log(('Ethereum development network running on port ' + config.dev.port).blue) + logger.info('Ethereum testing network running on port ' + config.dev.port) web3.eth.getAccounts().then(function(accounts){ compile(web3, accounts, "dev"); }) } else { - console.log('This is not a valid Parasol project. Please run "parasol init" in an empty directory to initialize a new project.'.red) + logger.error('This is not a valid Parasol project. Please run "parasol init" in an empty directory to initialize a new project.') } } @@ -263,7 +286,7 @@ global.deploy = function(network){ network = "mainnet" } var secrets = require(process.cwd()+'/secrets.json'); - console.log(('Deploying contracts to ' + network).blue) + logger.info('Deploying contracts to ' + network) compile(web3, secrets, network); } @@ -271,7 +294,7 @@ if(program.deploy) { if (fs.existsSync("./parasol.js")) { deploy(program.deploy) } else { - console.log('This is not a valid Parasol project. Please run "parasol init" in an empty directory to initialize a new project.'.red) + logger.error('This is not a valid Parasol project. Please run "parasol init" in an empty directory to initialize a new project.') } } @@ -288,11 +311,7 @@ if(program.interact) { global.web3 = new Web3(network); } - var addressbook = require(process.cwd()+'/addressbook.json'); - if(typeof addressbook[network] === "undefined") { - console.log(("There are no contracts registered for this network in your address book. Please make sure you deploy your contracts to " + network + " first").red) - process.exit() - } + addressbook.checkNetwork(network); var files = read(process.cwd() + '/ABI'); @@ -301,11 +320,11 @@ if(program.interact) { for (var i = 0; i < files.length; i++) { var newName = files[i].replace("_",".").replace("-",":").slice(0, -5) var interface = JSON.parse(fs.readFileSync(process.cwd() + "/ABI/" + files[i], 'utf8')); - contracts[newName] = new global.web3.eth.Contract(interface, addressbook[network][newName]) + contracts[newName] = new global.web3.eth.Contract(interface, addressbook.get()[network][newName]) } if(contracts.length === 0){ - console.log('There are are no contract interfaces in your ABI/ directory. Please deploy your contracts first'.red) + logger.error('There are are no contract interfaces in your ABI/ directory. Please deploy your contracts first') process.exit() } @@ -327,35 +346,16 @@ if(program.interact) { global.assertRevert = function(e) { global.assert(e.results[Object.keys(e.results)[0]].error, 'revert') } - console.log(('Parasol interacting with contracts on ' + network).blue) + logger.info('Parasol interacting with contracts on ' + network) replInstance = repl.start({ prompt: 'parasol> '.bold.cyan, useGlobal:true, ignoreUndefined:true, useColors:true }); replInstance.defineCommand('help', { action: function(){ - console.log(` -Parasol global variables: - web3 web3 1.0 already attached to the Ganache provider and 10 generated accounts funded with 100 ETH each - contracts Object of contract instances deployed on ganache. Key is relative location from contracts/ folder + ":" + contract name - address0 Short for 0x00000000000000000000000000000000000 also known as address(0) in solidity. Useful to reduce code redundancy - accounts Array of public Ethereum addresses of accounts attached to the above web3 instance - assert The native Node.js assertion module required for basic unit tests - assertRevert Special assertion function used to assert failure of a web3 send transaction. Takes a Promise error as an argument. -REPL commands: - .break Sometimes you get stuck, this gets you out - .clear Alias for .break - .editor Enter editor mode - .exit Exit the repl - .help Print this help message - .history Show the history - .load Load JS from a file into the REPL session - .save Save all evaluated commands in this REPL session to a file -Documentation: -https://developer.lamarkaz.com/parasol - `) + console.log(literals.interact) replInstance.displayPrompt() } }) replInstance.on('exit', () => { - console.log('Shutting down Parasol interaction console'.blue); + logger.info('Shutting down Parasol interaction console'); process.exit(); }); stubber(replInstance); diff --git a/init/ABI/Token_psol-Token.json b/init/ABI/Token_psol-Token.json new file mode 100644 index 0000000..6af34ae --- /dev/null +++ b/init/ABI/Token_psol-Token.json @@ -0,0 +1,168 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "forceTransfer", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x33bebb77" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "_balances", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6ebcf607" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } +] \ No newline at end of file diff --git a/init/contracts/Token.psol b/init/contracts/Token.psol new file mode 100644 index 0000000..35f75f0 --- /dev/null +++ b/init/contracts/Token.psol @@ -0,0 +1,110 @@ +pragma solidity ^0.4.24; + +{{ // strict = true }} +{{ // abort("just for fun") }} +{{ // ignore(this) }} + +/// @title {{= title }} +contract Token { + + string private _name = "{{= tokenName}}"; + string private _symbol = "{{= tokenSymbol}}"; + uint8 private _decimals = {{= tokenDecimals}}; + uint256 private _totalSupply = {{= tokenSupply}}; + + mapping (address => uint256) public _balances; + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + + constructor() public { + _balances[msg.sender] = _totalSupply; + } + + /** + * @dev Transfer token for a specified addresses + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool success) { + require(_balances[msg.sender] >= _value); + _balances[msg.sender] -= _value; + _balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); + return true; + } + + /// @author Nour Haridy + /// @dev Checks balance of address + /// @param _owner The queried address + /// @return balance of address + function balanceOf(address _owner) constant public returns (uint256 balance) { + return _balances[_owner]; + } + + /** + * @return the name of the token. + */ + function name() public view returns(string) { + return _name; + } + + /** + * @return the symbol of the token. + */ + function symbol() public view returns(string) { + return _symbol; + } + + /** + * @return the number of decimals of the token. + */ + function decimals() public view returns(uint8) { + return _decimals; + } + + // Preprocessor directive. Only compiles if in 'dev' network + {{ if (network === "dev") { }} + + /// @dev Force transfers tokens from any account to another. Only compiled in 'dev' network + /// @param _from The address of the transfer sender + /// @param _to The address of the transfer recipient + /// @param _value The amount of tokens to be transferred + /// @return true if tokens transferred successfully + function forceTransfer(address _from, address _to, uint256 _value) public returns (bool success) { + require(_balances[_from] >= _value); + _balances[_from] -= _value; + _balances[_to] += _value; + emit Transfer(_from, _to, _value); + return true; + } + + {{ } }} + +} + +{{ + + //parasol.onCompiled(this, function(fileName){ + // console.log("File: " + fileName + " compiled") + //}) + + //parasol.onError(this, function(e){ + // console.log("error: " + e) + //}) + + //parasol.onDeployed(this, function(contract, contractName){ + // console.log('Deployed') + //}) + + //parasol.onAllDeployed(async function(contracts){ + // console.log(await contracts["Token.psol:Token"].methods.balanceOf(accounts[0]).call()) + //}) + + test(this, 'Transfer() should change balance after transfer', async function() { + var preBalance = await contracts["Token.psol:Token"].methods.balanceOf(accounts[0]).call() + await contracts["Token.psol:Token"].methods.transfer(accounts[1], 1).send() + var postBalance = await contracts["Token.psol:Token"].methods.balanceOf(accounts[0]).call() + assert.notEqual(preBalance, postBalance) + }) + +}} diff --git a/init/contracts/Token.sol b/init/contracts/Token.sol deleted file mode 100644 index 5f9559c..0000000 --- a/init/contracts/Token.sol +++ /dev/null @@ -1,38 +0,0 @@ -pragma solidity ^0.4.24; - -/// @title A very minimal token contract -contract Token { - - uint256 public totalSupply = 1*10**28; - string public name = "Token"; - uint8 public decimals = 18; - string public symbol = "TOK"; - mapping (address => uint256) balances; - event Transfer(address indexed _from, address indexed _to, uint256 _value); - - constructor() public { - balances[msg.sender] = totalSupply; - } - - /// @author Nour Haridy - /// @dev Transfers tokens - /// @param _to The address of the transfer recipient - /// @param _value The amount of tokens to be transferred - /// @return true if tokens transferred successfully - function transfer(address _to, uint256 _value) public returns (bool success) { - require(balances[msg.sender] >= _value); - balances[msg.sender] -= _value; - balances[_to] += _value; - emit Transfer(msg.sender, _to, _value); - return true; - } - - /// @author Nour Haridy - /// @dev Checks balance of address - /// @param _owner The queried address - /// @return balance of address - function balanceOf(address _owner) constant public returns (uint256 balance) { - return balances[_owner]; - } - -} \ No newline at end of file diff --git a/init/docs/README.md b/init/docs/README.md index da9a604..c4387ed 100644 --- a/init/docs/README.md +++ b/init/docs/README.md @@ -1 +1,75 @@ + # Smart Contract Documentation + + +## [Token.psol:Token](../contracts/Token.psol) +`Solidity version 0.4.24+commit.e67f0147` +A minimal token contract + + ##### function name `0x06fdde03` + constant view + + +___ + ##### function decimals `0x313ce567` + constant view + + +___ + ##### function forceTransfer `0x33bebb77` + nonpayable +Force transfers tokens from any account to another. Only compiled in 'dev' network + + Type | Name | +--- | --- | +| address | _from | +| address | _to | +| uint256 | _value | +___ + ##### function _balances `0x6ebcf607` + constant view + + + Type | Name | +--- | --- | +| address | | +___ + ##### function balanceOf `0x70a08231` by Nour Haridy + constant view +Checks balance of address + + Type | Name | +--- | --- | +| address | _owner | +___ + ##### function symbol `0x95d89b41` + constant view + + +___ + ##### function transfer `0xa9059cbb` + nonpayable +Transfer token for a specified addresses + + Type | Name | +--- | --- | +| address | _to | +| uint256 | _value | +___ + ##### constructor `constructor` + nonpayable + + +___ + ##### event Transfer `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef` + + + + Type | Name | +--- | --- | +| address | _from | +| address | _to | +| uint256 | _value | +___ + +--- \ No newline at end of file diff --git a/init/parasol.js b/init/parasol.js index 2ec3fad..af71db0 100644 --- a/init/parasol.js +++ b/init/parasol.js @@ -7,7 +7,7 @@ module.exports = { //logger:console, gasPrice: 0 }, - contracts : "*", // To select specific contracts, replace it with an array: ["File1.sol", "Folder/File2.sol"] + contracts : "*", // To select specific contract locations, replace it with an array: ["File1.sol", "Folder/File2.sol"] solc: { // Solidity compiler options (https://solidity.readthedocs.io/en/develop/using-the-compiler.html) optimizer: { enabled: true, @@ -31,14 +31,29 @@ module.exports = { } } }, + preprocessor: { + context: { + title: "A minimal token contract", + tokenSupply: "1*10**28", + tokenName: "Token", + tokenDecimals:18, + tokenSymbol: "TOK" + }, + settings: { // Underscore.js.template settings. Read more: https://underscorejs.org/#template + evaluate: /{{([\s\S]+?)}}/g, + interpolate: /{{=([\s\S]+?)}}/g, + escape: /{{-([\s\S]+?)}}/g + }, + strict: false // If true, strict mode will abort deployment on warnings as well as errors + }, deployer: async function (contracts, network, web3, test, save) { for (var contract in contracts) { var gasPrice = "50000000000"; //50 Gwei if(network === "dev") { gasPrice = "0"; } - contracts[contract] = await contracts[contract].deploy().send({from: web3.eth.accounts[0], gasPrice, gas:1000000}) - console.log(contract + " deployed at address " + contracts[contract].options.address) + contracts[contract] = await contracts[contract].deploy().send({from: web3.eth.accounts[0], gasPrice, gas:6000000}) + console.log(("Contract " + contract + " deployed at address " + contracts[contract].options.address).green) } save(contracts) // Saves contract addresses to addressbook.json. Development addresses will never be saved to addressbook. test(contracts) // Call the test function if you want to run unit tests after deployment. Tests will only run if network is dev diff --git a/init/tests/Token.js b/init/tests/Token.js index 8f067f6..827944b 100644 --- a/init/tests/Token.js +++ b/init/tests/Token.js @@ -1,7 +1,7 @@ -describe('Token.sol', function() { +describe('Token.psol', function() { describe('Transfer()', function() { it('should revert when transferred amount is smaller than 0', function() { - contracts['Token.sol:Token'].methods.transfer(address0, -1).send().on('error', (e) => assertRevert(e)) + contracts['Token.psol:Token'].methods.transfer(address0, -1).send().on('error', (e) => assertRevert(e)) }); }); }); \ No newline at end of file diff --git a/literals/index.js b/literals/index.js new file mode 100644 index 0000000..6702b6c --- /dev/null +++ b/literals/index.js @@ -0,0 +1,45 @@ +module.exports = { + interact: ` +Parasol global variables: + web3 web3 1.0 already attached to the Ganache provider and 10 generated accounts funded with 100 ETH each + contracts Object of contract instances deployed on ganache. Key is relative location from contracts/ folder + ":" + contract name + address0 Short for 0x00000000000000000000000000000000000 also known as address(0) in solidity. Useful to reduce code redundancy + accounts Array of public Ethereum addresses of accounts attached to the above web3 instance + assert The native Node.js assertion module required for basic unit tests + assertRevert Special assertion function used to assert failure of a web3 send transaction. Takes a Promise error as an argument. +REPL commands: + .break Sometimes you get stuck, this gets you out + .clear Alias for .break + .editor Enter editor mode + .exit Exit the repl + .help Print this help message + .history Show the history + .load Load JS from a file into the REPL session + .save Save all evaluated commands in this REPL session to a file +Documentation: +https://developer.lamarkaz.com/parasol + `, + dev: ` +Parasol global variables: + web3 web3 1.0 already attached to the Ganache provider and 10 generated accounts funded with 100 ETH each + contracts Object of contract instances deployed on ganache. Key is relative location from contracts/ folder + ":" + contract name + address0 Short for 0x00000000000000000000000000000000000 also known as address(0) in solidity. Useful to reduce code redundancy + accounts Array of public Ethereum addresses of accounts attached to the above web3 instance + assert The native Node.js assertion module required for basic unit tests + assertRevert Special assertion function used to assert failure of a web3 send transaction. Takes a Promise error as an argument. +Parasol commands: + .recompile Recompile all contracts, redeploy on devnet, recompile docs & run tests + .deploy .deploy [network] will deploy contracts to [network] (Default network is mainnet) +REPL commands: + .break Sometimes you get stuck, this gets you out + .clear Alias for .break + .editor Enter editor mode + .exit Exit the repl + .help Print this help message + .history Show the history + .load Load JS from a file into the REPL session + .save Save all evaluated commands in this REPL session to a file +Documentation: + https://developer.lamarkaz.com/parasol + ` +} \ No newline at end of file diff --git a/logger/index.js b/logger/index.js new file mode 100644 index 0000000..ad49c93 --- /dev/null +++ b/logger/index.js @@ -0,0 +1,17 @@ +var colors = require('colors'); +const logSymbols = require('log-symbols'); + +module.exports = { + error: function (msg) { + console.log(logSymbols.error, msg.red) + }, + warn: function (msg) { + console.log(logSymbols.warn, msg.yellow) + }, + info: function (msg) { + console.log(logSymbols.info, msg.blue) + }, + success: function (msg) { + console.log(logSymbols.success, msg.green) + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e7df72f..8d2a65b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,35 @@ { "name": "parasol-cli", - "version": "1.0.2", + "version": "1.1.8", "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=", + "requires": { + "@types/node": "9.6.35" + } + }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", + "requires": { + "@types/node": "9.6.35" + } + }, + "@types/node": { + "version": "9.6.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.35.tgz", + "integrity": "sha512-h5zvHS8wXHGa+Gcqs9K8vqCgOtqjr0+NqG/DDJmQIX1wpR9HivAfgV8bjcD3mGM4bPfQw5Aneb2Pn8355L83jA==" + }, + "@types/qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q==" + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -39,6 +65,14 @@ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.3" + } + }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -49,6 +83,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -377,6 +416,16 @@ "lazy-cache": "1.0.4" } }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -444,6 +493,19 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, "colors": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", @@ -467,6 +529,17 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -1166,6 +1239,11 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -1307,6 +1385,19 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, + "http-basic": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-7.0.0.tgz", + "integrity": "sha1-gvClBr6UJzLsje6+6A50bvVzbbo=", + "requires": { + "@types/concat-stream": "1.6.0", + "@types/node": "9.6.35", + "caseless": "0.12.0", + "concat-stream": "1.6.2", + "http-response-object": "3.0.1", + "parse-cache-control": "1.0.1" + } + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -1323,6 +1414,14 @@ "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" }, + "http-response-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.1.tgz", + "integrity": "sha512-6L0Fkd6TozA8kFSfh9Widst0wfza3U1Ex2RjJ6zNDK0vR1U1auUR6jY4Nn2Xl7CCy0ikFmxW1XcspVpb9RvwTg==", + "requires": { + "@types/node": "9.6.35" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -1566,6 +1665,14 @@ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "requires": { + "chalk": "2.4.1" + } + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -1895,6 +2002,11 @@ "pbkdf2": "3.0.16" } }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=" + }, "parse-headers": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.1.tgz", @@ -2012,6 +2124,14 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, + "promise": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", + "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", + "requires": { + "asap": "2.0.6" + } + }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -2026,6 +2146,15 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, + "psol": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/psol/-/psol-1.0.9.tgz", + "integrity": "sha512-RK15TryWilySwBfdj7E5A/97ppPSWPaKWeIS8gEhUz2rJCDi69V8/4ym01OV5XOI7PgkmQ1HPwl+f7ZncW9jmw==", + "requires": { + "sync-request": "6.0.0", + "underscore.template": "0.1.7" + } + }, "public-encrypt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", @@ -2193,6 +2322,11 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, + "resnap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resnap/-/resnap-1.0.1.tgz", + "integrity": "sha512-INWHhTlHwkl0h9m1MMYBgZmatCLoQwMmeijEyTjEOPXcBBgCfAxskSNAUDLL/lO1PB+evr5FsJ8Y8K+GLkpV3A==" + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -2595,6 +2729,24 @@ } } }, + "sync-request": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.0.0.tgz", + "integrity": "sha512-jGNIAlCi9iU4X3Dm4oQnNQshDD3h0/1A7r79LyqjbjUnj69sX6mShAXlhRXgImsfVKtTcnra1jfzabdZvp+Lmw==", + "requires": { + "http-response-object": "3.0.1", + "sync-rpc": "1.3.4", + "then-request": "6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.4.tgz", + "integrity": "sha512-Iug+t1ICVFenUcTnDu8WXFnT+k8IVoLKGh8VA3eXUtl2Rt9SjKX3YEv33OenABqpTPL9QEaHv1+CNn2LK8vMow==", + "requires": { + "get-port": "3.2.0" + } + }, "tar": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", @@ -2638,6 +2790,31 @@ } } }, + "then-request": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.0.tgz", + "integrity": "sha512-xA+7uEMc+jsQIoyySJ93Ad08Kuqnik7u6jLS5hR91Z3smAoCfL3M8/MqMlobAa9gzBfO9pA88A/AntfepkkMJQ==", + "requires": { + "@types/concat-stream": "1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "8.10.36", + "@types/qs": "6.5.1", + "caseless": "0.12.0", + "concat-stream": "1.6.2", + "form-data": "2.3.2", + "http-basic": "7.0.0", + "http-response-object": "3.0.1", + "promise": "8.0.2", + "qs": "6.5.2" + }, + "dependencies": { + "@types/node": { + "version": "8.10.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.36.tgz", + "integrity": "sha512-SL6KhfM7PTqiFmbCW3eVNwVBZ+88Mrzbuvn9olPsfv43mbiWaFY+nRcz/TGGku0/lc2FepdMbImdMY1JrQ+zbw==" + } + } + }, "thenify": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", @@ -2706,6 +2883,11 @@ "mime-types": "2.1.20" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -2810,6 +2992,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" }, + "underscore.template": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/underscore.template/-/underscore.template-0.1.7.tgz", + "integrity": "sha1-MBPg6hgXVjBvFgnpWcr7xyKts+k=" + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index 7656a18..e946cd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parasol-cli", - "version": "1.1.8", + "version": "2.0.0", "description": "Powerful Smart Contract Development Environment", "main": "index.js", "bin": { @@ -34,10 +34,14 @@ "ganache-cli": "^6.1.8", "handlebars": "^4.0.11", "jsonfile": "^5.0.0", + "log-symbols": "^2.2.0", "mocha": "^5.2.0", "node-watch": "^0.5.8", + "psol": "^1.0.9", + "resnap": "^1.0.1", "rimraf": "^2.6.2", "solc": "^0.4.24", + "underscore.template": "^0.1.7", "web3": "^1.0.0-beta.35" } }