diff --git a/src/lib/modules/contracts_manager/index.js b/src/lib/modules/contracts_manager/index.js index e57266b16..ffbb2b6c0 100644 --- a/src/lib/modules/contracts_manager/index.js +++ b/src/lib/modules/contracts_manager/index.js @@ -332,6 +332,7 @@ class ContractsManager { contract.code = compiledContract.code; contract.runtimeBytecode = compiledContract.runtimeBytecode; contract.realRuntimeBytecode = (compiledContract.realRuntimeBytecode || compiledContract.runtimeBytecode); + contract.linkReferences = compiledContract.linkReferences; contract.swarmHash = compiledContract.swarmHash; contract.gasEstimates = compiledContract.gasEstimates; contract.functionHashes = compiledContract.functionHashes; @@ -467,12 +468,13 @@ class ContractsManager { self.contractDependencies[className] = self.contractDependencies[className].concat(contract.deps); } - // look in code for dependencies - if (contract.code) { - let libMatches = (contract.code.match(/:(.*?)(?=_)/g) || []); - for (let match of libMatches) { - self.contractDependencies[className].push(match.substr(1)); - } + // look in linkReferences for dependencies + if (contract.linkReferences) { + Object.values(contract.linkReferences).forEach(fileReference => { + Object.keys(fileReference).forEach(libName => { + self.contractDependencies[className].push(libName); + }); + }); } // look in arguments for dependencies diff --git a/src/lib/modules/deployment/contract_deployer.js b/src/lib/modules/deployment/contract_deployer.js index 80d10f463..ab573af34 100644 --- a/src/lib/modules/deployment/contract_deployer.js +++ b/src/lib/modules/deployment/contract_deployer.js @@ -209,32 +209,46 @@ class ContractDeployer { async.waterfall([ function doLinking(next) { + + if (!contract.linkReferences || !Object.keys(contract.linkReferences).length) { + return next(); + } let contractCode = contract.code; - self.events.request('contracts:list', (_err, contracts) => { - for (let contractObj of contracts) { - let filename = contractObj.filename; - let deployedAddress = contractObj.deployedAddress; - if (deployedAddress) { - deployedAddress = deployedAddress.substr(2); - } - let linkReference = '__' + filename + ":" + contractObj.className; - if (contractCode.indexOf(linkReference.substr(0, 38)) < 0) { // substr to simulate the cut that solc does - continue; - } - if (linkReference.length > 40) { - return next(new Error(__("{{linkReference}} is too long, try reducing the path of the contract ({{filename}}) and/or its name {{contractName}}", {linkReference: linkReference, filename: filename, contractName: contractObj.className}))); - } - let toReplace = linkReference + "_".repeat(40 - linkReference.length); - if (deployedAddress === undefined) { - let libraryName = contractObj.className; - return next(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {contractName: contract.className, libraryName: libraryName}))); - } - contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress); - } - // saving code changes back to the contract object + let offset = 0; + + async.eachLimit(contract.linkReferences, 1, (fileReference, eachCb1) => { + async.eachOfLimit(fileReference, 1, (references, libName, eachCb2) => { + self.events.request("contracts:contract", libName, (libContract) => { + async.eachLimit(references, 1, (reference, eachCb3) => { + if (!libContract) { + return eachCb3(new Error(__('{{contractName}} has a link to the library {{libraryName}}, but it was not found. Is it in your contract folder?'), { + contractName: contract.className, + libraryName: libName + })); + } + + let libAddress = libContract.deployedAddress; + if (!libAddress) { + return eachCb3(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", { + contractName: contract.className, + libraryName: libName + }))); + } + + libAddress = libAddress.substr(2).toLowerCase(); + + // Multiplying by two because the original pos and length are in bytes, but we have an hex string + contractCode = contractCode.substring(0, (reference.start * 2) + offset) + libAddress + contractCode.substring((reference.start * 2) + offset + (reference.length * 2)); + // Calculating an offset in case the length is at some point different than the address length + offset += libAddress.length - (reference.length * 2); + + eachCb3(); + }, eachCb2); + }); + }, eachCb1); + }, (err) => { contract.code = contractCode; - self.events.request('contracts:setBytecode', contract.className, contractCode); - next(); + next(err); }); }, function applyBeforeDeploy(next) { diff --git a/src/lib/modules/solidity/index.js b/src/lib/modules/solidity/index.js index 08f028bbd..d7d6f342e 100644 --- a/src/lib/modules/solidity/index.js +++ b/src/lib/modules/solidity/index.js @@ -136,6 +136,7 @@ class Solidity { compiled_object[className] = {}; compiled_object[className].code = contract.evm.bytecode.object; + compiled_object[className].linkReferences = contract.evm.bytecode.linkReferences; compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object; compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68); compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);