diff --git a/VERSIONS.md b/VERSIONS.md index a7403fc..ab28c36 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -1,10 +1,15 @@ -# smart-contracts +# smart-contracts-core ## Next Version ### Features ### Fixes ### Deprecations +## Version 1.1.1 +### Fixes +- use `keccak256` instead of `sha3` for hashing +- add `dst` argument to `lib/solc.js` functions to bypass config for destination path + ## Version 1.1.0 ### Fixes - update hasing to `keccak256` @@ -20,6 +25,7 @@ - add factory for `MultiSigWallet` contracts - change call and answer storage formate in `ServiceContract.sol` to structs - add more properties to result of `getCalls` and `getAnswers` in `ServiceContract.sol` +- add `registerFactory(address factoryId)` to `BusinessCenterInterface` ### Fixes - remove `MultiSigWallet` dependency by copying `.sol` file into contracts folder, to prevent `npm install` issues, when used as a subdependency diff --git a/contracts/BaseContract.sol b/contracts/BaseContract.sol index e0f9a64..48506f1 100755 --- a/contracts/BaseContract.sol +++ b/contracts/BaseContract.sol @@ -29,11 +29,11 @@ import "./ProfileIndexInterface.sol"; contract BaseContract is BaseContractInterface, EnsReader { uint8 private constant MEMBER_ROLE = 1; - // web3.sha3('contacts') + // web3.utils.soliditySha3('contacts') bytes32 private constant CONTACTS_LABEL = 0x8417ef2e3e7bb6630d90a4cdcc188db4bcc27d6b2d8891b376ef771499bb4299; - // web3.sha3('eventhub') + // web3.utils.soliditySha3('eventhub') bytes32 private constant EVENTHUB_LABEL = 0xea14ea6d138254c1a2931c6a19f6888c7b52f512d165cfa428183a53dd9dfb8c; - // web3.sha3('profile') + // web3.utils.soliditySha3('profile') bytes32 private constant PROFILE_LABEL = 0xe3dd854eb9d23c94680b3ec632b9072842365d9a702ab0df7da8bc398ee52c7d; function BaseContract(address _provider, bytes32 _contractType, bytes32 _contractDescription, address ensAddress) { diff --git a/contracts/BusinessCenterInterface.sol b/contracts/BusinessCenterInterface.sol index 0a96e69..6f037cd 100755 --- a/contracts/BusinessCenterInterface.sol +++ b/contracts/BusinessCenterInterface.sol @@ -47,6 +47,7 @@ contract BusinessCenterInterface is Owned { function migrateTo(address) public; function sendContractEvent(uint evetType, bytes32 contractType, address member) public; function getProfile(address account) public constant returns (bytes32); + function registerFactory(address factoryId) public; function setMyProfile(bytes32 profile) public; function setJoinSchema(JoinSchema) public; diff --git a/contracts/DataContract.sol b/contracts/DataContract.sol index d4d69fc..719d3ef 100755 --- a/contracts/DataContract.sol +++ b/contracts/DataContract.sol @@ -27,26 +27,26 @@ import "./DSRolesPerContract.sol"; /// @notice this is a contract with abstract functions that is used as an interface for DataContracts /// @dev requires calling "init" before usage contract DataContract is DataContractInterface, BaseContract { - //// labels for buildig sha3 keys - // web3.sha3('subcontracts') + //// labels for buildig keccak256 keys + // web3.utils.soliditySha3('subcontracts') bytes32 public constant SUBCONTRACTS_LABEL = 0x33baa6f316fab89cb11f57cf36f92fc446eeabbee455d30c346989e18dba49c4; - // web3.sha3('entry') + // web3.utils.soliditySha3('entry') bytes32 public constant ENTRY_LABEL = 0x84f3db82fb6cd291ed32c6f64f7f5eda656bda516d17c6bc146631a1f05a1833; - // web3.sha3('listentry') + // web3.utils.soliditySha3('listentry') bytes32 public constant LISTENTRY_LABEL = 0x7da2a80303fd8a8b312bb0f3403e22702ece25aa85a5e213371a770a74a50106; - // web3.sha3('mappingentry') + // web3.utils.soliditySha3('mappingentry') bytes32 public constant MAPPINGENTRY_LABEL = 0xd9234c2c276ff426c50a259dd40abb4cdd9767973f4a72f6e032e829f681e0b4; - // web3.sha3('contractstate') + // web3.utils.soliditySha3('contractstate') bytes32 public constant CONTRACTSTATE_LABEL = 0xf0af2cee3e7130dfb5ef02ebfaf64a30da17e9c9c26d3d40ece69a2e0ee1d69e; - // web3.sha3('ownstate') + // web3.utils.soliditySha3('ownstate') bytes32 public constant OWNSTATE_LABEL = 0x56ead3438bd16b0aaea9b0b78119b1db8a5382b496db7a1989fe7a32f9890f7c; - // web3.sha3('othersstate') + // web3.utils.soliditySha3('othersstate') bytes32 public constant OTHERSSTATE_LABEL = 0xa287c88bf56474b8c2de2568111316e26d1b3572718b1a8cdf0c881a767e4cb7; - // web3.sha3('count') + // web3.utils.soliditySha3('count') bytes32 public constant COUNT_LABEL = 0xc82306b6ab1b4c67429442feb1e6d238135a6cfcaa471a01b0e336f01b048e38; - // web3.sha3('set') + // web3.utils.soliditySha3('set') bytes32 public constant SET_LABEL = 0xd2f67e6aeaad1ab7487a680eb9d3363a597afa7a3de33fa9bf3ae6edcb88435d; - // web3.sha3('remove') + // web3.utils.soliditySha3('remove') bytes32 public constant REMOVE_LABEL = 0x8dd27a19ebb249760a6490a8d33442a54b5c3c8504068964b74388bfe83458be; // data storage @@ -73,7 +73,7 @@ contract DataContract is DataContractInterface, BaseContract { /// @notice add entries to a list /// @dev keep in mind that list do not provide a fixed order; /// they can be iterated, but deleting entries repositions items - /// @param keys sha3 hashes of the list names + /// @param keys keccak256 hashes of the list names /// @param values values to add to this list function addListEntries(bytes32[] keys, bytes32[] values) public auth { for (uint256 i = 0; i < keys.length; i++) { @@ -133,9 +133,9 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice move a list entry from a list into one or multiple lists - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @param index index of the element to delete - /// @param keys sha3 hashes of the list names + /// @param keys keccak256 hashes of the list names function moveListEntry(bytes32 key, uint256 index, bytes32[] keys) public auth { bytes32[] memory values = new bytes32[](1); values[0] = getListEntry(key, index); @@ -145,7 +145,7 @@ contract DataContract is DataContractInterface, BaseContract { /// @notice remove a list entry from a list /// @dev moves last element from list into the slot where the deleted entry was placed - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @param index index of the element to delete function removeListEntry(bytes32 key, uint256 index) public auth { // create key for list ('$KEY.listentry') @@ -166,7 +166,7 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice set a value of an entry in the contract - /// @param key sha3 hash of a key + /// @param key keccak256 hash of a key /// @param value value to set for this key function setEntry(bytes32 key, bytes32 value) public auth { // create key for entry @@ -179,8 +179,8 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice set a value of a mapping property in the contract - /// @param mappingHash sha3 hash of the mapping name - /// @param key sha3 hash of the mappings entry/property name + /// @param mappingHash keccak256 hash of the mapping name + /// @param key keccak256 hash of the mappings entry/property name /// @param value value to set for this key function setMappingValue(bytes32 mappingHash, bytes32 key, bytes32 value) public auth { // create key for mapping ('$KEY.listentry') @@ -194,7 +194,7 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice retrieve entry value for a key - /// @param key sha3 hash of a key + /// @param key keccak256 hash of a key /// @return value for this key function getEntry(bytes32 key) public constant returns(bytes32) { // return entry @@ -202,7 +202,7 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice get number of elements in a list - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @return number of elements function getListEntryCount(bytes32 key) public constant returns(uint256) { // return entry ('listcount.$KEY.listentry') @@ -210,7 +210,7 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice retrieve a single entry from a list - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @param index index of the element to retrieve /// @return value for this list entry function getListEntry(bytes32 key, uint256 index) public constant returns(bytes32) { @@ -219,8 +219,8 @@ contract DataContract is DataContractInterface, BaseContract { } /// @notice retrieve a single entry from a mapping - /// @param mappingHash sha3 hash of the mapping name - /// @param key sha3 hash of the mappings entry/property name + /// @param mappingHash keccak256 hash of the mapping name + /// @param key keccak256 hash of the mappings entry/property name /// @return value for this mapping entry function getMappingValue(bytes32 mappingHash, bytes32 key) public constant returns(bytes32) { // return entry ('$KEY.$MAPPING.listentry') diff --git a/contracts/DataContractInterface.sol b/contracts/DataContractInterface.sol index 943f414..82fe551 100755 --- a/contracts/DataContractInterface.sol +++ b/contracts/DataContractInterface.sol @@ -28,7 +28,7 @@ contract DataContractInterface is BaseContractInterface { /// @notice add entries to a list /// @dev keep in mind that list do not provide a fixed order; /// they can be iterated, but deleting entries repositions items - /// @param keys sha3 hash of the list name + /// @param keys keccak256 hash of the list name /// @param values values to add to this list function addListEntries(bytes32[] keys, bytes32[] values) public; @@ -51,47 +51,47 @@ contract DataContractInterface is BaseContractInterface { function init(bytes32 domain, bool allowConsumerInviteIn) public; /// @notice move a list entry from a list into one or multiple lists - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @param index index of the element to delete - /// @param keys sha3 hashes of the list names + /// @param keys keccak256 hashes of the list names function moveListEntry(bytes32 key, uint256 index, bytes32[] keys) public; /// @notice remove a list entry from a list /// @dev moves last element from list into the slot where the deleted entry was placed - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @param index index of the element to delete function removeListEntry(bytes32 key, uint256 index) public; /// @notice set a value of an entry in the contract - /// @param key sha3 hash of a key + /// @param key keccak256 hash of a key /// @param value value to set for this key function setEntry(bytes32 key, bytes32 value) public; /// @notice set a value of a mapping property in the contract - /// @param mappingHash sha3 hash of the mapping name - /// @param key sha3 hash of the mappings entry/property name + /// @param mappingHash keccak256 hash of the mapping name + /// @param key keccak256 hash of the mappings entry/property name /// @param value value to set for this key function setMappingValue(bytes32 mappingHash, bytes32 key, bytes32 value) public; /// @notice retrieve entry value for a key - /// @param key sha3 hash of a key + /// @param key keccak256 hash of a key /// @return value for this key function getEntry(bytes32 key) public constant returns(bytes32); /// @notice get number of elements in a list - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @return number of elements function getListEntryCount(bytes32 key) public constant returns(uint256); /// @notice retrieve a single entry from a list - /// @param key sha3 hash of the list name + /// @param key keccak256 hash of the list name /// @param index index of the element to retrieve /// @return value for this list entry function getListEntry(bytes32 key, uint256 index) public constant returns(bytes32); /// @notice retrieve a single entry from a mapping - /// @param mappingHash sha3 hash of the mapping name - /// @param key sha3 hash of the mappings entry/property name + /// @param mappingHash keccak256 hash of the mapping name + /// @param key keccak256 hash of the mappings entry/property name /// @return value for this mapping entry function getMappingValue(bytes32 mappingHash, bytes32 key) public constant returns(bytes32); } diff --git a/contracts/EnsReader.sol b/contracts/EnsReader.sol index 0b6c995..257878a 100755 --- a/contracts/EnsReader.sol +++ b/contracts/EnsReader.sol @@ -31,7 +31,7 @@ contract EnsReader { bytes32 rootDomain = 0x01713a3bd6dccc828bbc37b3f42f3bc5555b16438783fabea9faf8c2243a0370; function getAddr(bytes32 node) constant internal returns (address) { - return AbstractPublicResolver(ens.resolver(sha3(rootDomain, node))).addr(sha3(rootDomain, node)); + return AbstractPublicResolver(ens.resolver(keccak256(rootDomain, node))).addr(keccak256(rootDomain, node)); } function setEns(address ensAddress) internal { diff --git a/contracts/ServiceContract.sol b/contracts/ServiceContract.sol index f4316cb..af224c9 100755 --- a/contracts/ServiceContract.sol +++ b/contracts/ServiceContract.sol @@ -25,7 +25,7 @@ import "./ServiceContractInterface.sol"; contract ServiceContract is ServiceContractInterface, BaseContract { bytes32 public constant EVENTHUB_LABEL = - 0xea14ea6d138254c1a2931c6a19f6888c7b52f512d165cfa428183a53dd9dfb8c; //web3.sha3('events') + 0xea14ea6d138254c1a2931c6a19f6888c7b52f512d165cfa428183a53dd9dfb8c; //web3.utils.soliditySha3('events') function ServiceContract(address _provider, bytes32 _contractType, bytes32 _contractDescription, address ensAddress) public BaseContract(_provider, _contractType, _contractDescription, ensAddress) { diff --git a/dbcp.json b/dbcp.json index f753f80..c5f2c7b 100644 --- a/dbcp.json +++ b/dbcp.json @@ -16,7 +16,7 @@ "contractus", "library" ], - "version": "1.1.0", + "version": "1.1.1", "versions": { "0.1.0": "QmQ576qcoH4GXKRTYq3xqYJR62Lhf5665ySTj6YyENMZPJ", "0.9.0": "QmNfBLnAM4DctyNxg7CbE4mtYdmQfTN9bVGx8x12nMvjUD", diff --git a/lib/solc.js b/lib/solc.js index 6c631f3..ab8ad9b 100755 --- a/lib/solc.js +++ b/lib/solc.js @@ -12,16 +12,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - - */ const {promisify} = require('util') const fs = require('fs') -const rread = require('fs-readdir-recursive') -const solc = require('solc') const path = require('path') + const findup = require('findup-sync') +const rread = require('fs-readdir-recursive') +const solc = require('solc') + const errorPattern = /^.*error:/i; const filenamePattern = /^([^:]+)(?:\s|.)*$/; @@ -34,6 +34,11 @@ const compiledFile = 'compiled.json' const compiledJSFile = 'compiled.js' class Solc { + /** + * creates new Solc instance + * + * @param {any} options supports properties: compileContracts, destinationPath + */ constructor(options) { this.log = options.log; this.config = Object.assign({}, options.config); @@ -45,47 +50,24 @@ class Solc { !fs.existsSync(path.resolve( this.config.destinationPath, compiledFile))) this.config.destinationPath = compiledPath else if(Array.isArray(this.config.destinationPath)) { - this.config.destinationPath.push(compiledPath) - for(let d of this.config.destinationPath) + for(let d of this.config.destinationPath) { if(fs.existsSync(path.resolve( d, compiledFile))) { this.config.destinationPath = d break; } + } + if (typeof this.config.destinationPath !== 'string') { + this.config.destinationPath = compiledPath; + } } } - async writeContractsToFile(contracts) { - - let fn = 'fn' - let jsfn = 'jsfn' - const content = JSON.stringify(contracts) - // remove bytecode from frontend file - Object.keys(contracts).forEach((key) => { delete contracts[key].bytecode }) - - // write contracts file into an seperated javascript file to be able to include it - // into a systemjs build - const jscontent = `(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module === 'object' && module.exports) { - module.exports = factory(); - } else { - root.returnExports = factory(); - } - }(typeof self !== 'undefined' ? self : this, function () { - return ${JSON.stringify(contracts)}; - }));` - if (this.config.destinationPath) { - const fn = path.resolve( this.config.destinationPath, compiledFile) - const jsfn = path.resolve( this.config.destinationPath, compiledJSFile) - if (!fs.existsSync(this.config.destinationPath)) fs.mkdirSync(this.config.destinationPath) - await Promise.all( [ promisify(fs.writeFile)( fn, content), - promisify(fs.writeFile)(jsfn, jscontent) ]) - - } - return { fn: content, jsfn: jscontent } - } - + /** + * compile contracts + * + * @param {any} src_tree object with folders and their file list as key, value + * @return {Promise} object with fn (.js content) and .jsfn (.json content) + */ async compileContracts(src_tree) { this.log('Compile Solidity contracts...') const solFiles = {} @@ -130,11 +112,19 @@ class Solc { return this.writeContractsToFile(trimmed) } - // when passing a destinationPath here, it must be a single path, it doesn't need to exist - // it will be created + /** + * ensure, that compiled contracts are at given folder or at default folder and that compiled + * contract code is up to date with latest .sol file modifications + * + * @param {string[]} additionalPaths list of folder to check for .sol files + * @param {string} dst (optional) target folder, it doesn't need to + * exist, it will be created, uses constructor + * config property 'destinationPath' by default + * @return {Promise} resolved when done + */ async ensureCompiled(additionalPaths = [], dst) { - this.config.destinationPath = dst || this.config.destinationPath - const ofile = path.resolve( this.config.destinationPath, compiledFile ) + let destinationPath = typeof dst === 'string' ? dst : this.config.destinationPath + const ofile = path.resolve(destinationPath, compiledFile) const compiled = fs.existsSync(ofile) if (!(this.config.compileContracts || !compiled)) return @@ -173,11 +163,17 @@ class Solc { return await Promise.all(stats.reduce((i,a) => a.concat(i) ,[])) .then(() => this.log('nothing to compile')) .catch((f) => { this.log(f, ' changed, Recompile all ...'); return this.compileContracts(src_tree); } ) - } - getContracts() { - const contracts = require(path.resolve(this.config.destinationPath, compiledFile)) + /** + * get compiled contracts, does not compile or recompile them + * + * @param {string} dst (optional) target folder, uses constructor config property + * 'destinationPath' by default + */ + getContracts(dst) { + let destinationPath = typeof dst === 'string' ? dst : this.config.destinationPath + const contracts = require(path.resolve(destinationPath, compiledFile)) const shortenedContracts = {} Object.keys(contracts).forEach((key) => { const contractKey = (key.indexOf(':') !== -1) ? key.split(':')[1] : key @@ -185,6 +181,45 @@ class Solc { }) return shortenedContracts } + + /** + * write given contracts to .js and .json file + * + * @param {any} contracts object with keys for contract defintions and values as + * abi array + * @param {string} dst (optional) target folder, uses constructor config + * property 'destinationPath' by default + * @return {Promise} object with fn (.js content) and .jsfn (.json content) + */ + async writeContractsToFile(contracts, dst) { + let destinationPath = typeof dst === 'string' ? dst : this.config.destinationPath + const content = JSON.stringify(contracts) + // remove bytecode from frontend file + Object.keys(contracts).forEach((key) => { delete contracts[key].bytecode }) + + // write contracts file into an seperated javascript file to be able to include it + // into a systemjs build + const jscontent = `(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(); + } else { + root.returnExports = factory(); + } + }(typeof self !== 'undefined' ? self : this, function () { + return ${JSON.stringify(contracts)}; + }));` + if (destinationPath) { + const fn = path.resolve(destinationPath, compiledFile) + const jsfn = path.resolve(destinationPath, compiledJSFile) + if (!fs.existsSync(destinationPath)) fs.mkdirSync(destinationPath) + await Promise.all( [ promisify(fs.writeFile)( fn, content), + promisify(fs.writeFile)(jsfn, jscontent) ]) + + } + return { fn: content, jsfn: jscontent } + } } module.exports = Solc diff --git a/package.json b/package.json index 3165ab0..042767b 100644 --- a/package.json +++ b/package.json @@ -32,5 +32,5 @@ "scripts": { "build-docu": "node ./scripts/build-docu.js" }, - "version": "1.1.0" + "version": "1.1.1" } \ No newline at end of file