commit
c1a3c52fcc
@ -1,248 +0,0 @@ |
|||||||
'use strict' |
|
||||||
var ethJSABI = require('ethereumjs-abi') |
|
||||||
var ethJSUtil = require('ethereumjs-util') |
|
||||||
var BN = ethJSUtil.BN |
|
||||||
var remixLib = require('remix-lib') |
|
||||||
var helper = remixLib.execution.txHelper |
|
||||||
var TreeView = require('remix-debugger').ui.TreeView |
|
||||||
var executionContext = require('../../execution-context') |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
|
|
||||||
/** |
|
||||||
* build the transaction data |
|
||||||
* |
|
||||||
* @param {Object} function abi |
|
||||||
* @param {Object} values to encode |
|
||||||
* @param {String} contractbyteCode |
|
||||||
*/ |
|
||||||
encodeData: function (funABI, values, contractbyteCode) { |
|
||||||
var encoded |
|
||||||
var encodedHex |
|
||||||
try { |
|
||||||
encoded = helper.encodeParams(funABI, values) |
|
||||||
encodedHex = encoded.toString('hex') |
|
||||||
} catch (e) { |
|
||||||
return { error: 'cannot encode arguments' } |
|
||||||
} |
|
||||||
if (contractbyteCode) { |
|
||||||
return { data: contractbyteCode + encodedHex } |
|
||||||
} else { |
|
||||||
return { data: Buffer.concat([helper.encodeFunctionId(funABI), encoded]).toString('hex') } |
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
/** |
|
||||||
* build the transaction data |
|
||||||
* |
|
||||||
* @param {String} contractName |
|
||||||
* @param {Object} contract - abi definition of the current contract. |
|
||||||
* @param {Object} contracts - map of all compiled contracts. |
|
||||||
* @param {Bool} isConstructor - isConstructor. |
|
||||||
* @param {Object} funAbi - abi definition of the function to call. null if building data for the ctor. |
|
||||||
* @param {Object} params - input paramater of the function to call |
|
||||||
* @param {Object} udapp - udapp |
|
||||||
* @param {Function} callback - callback |
|
||||||
* @param {Function} callbackStep - callbackStep |
|
||||||
*/ |
|
||||||
buildData: function (contractName, contract, contracts, isConstructor, funAbi, params, udapp, callback, callbackStep) { |
|
||||||
var funArgs = '' |
|
||||||
var data = '' |
|
||||||
var dataHex = '' |
|
||||||
|
|
||||||
if (params.indexOf('0x') === 0) { |
|
||||||
dataHex = params.replace('0x', '') |
|
||||||
data = Buffer.from(dataHex, 'hex') |
|
||||||
} else { |
|
||||||
try { |
|
||||||
funArgs = JSON.parse('[' + params + ']') |
|
||||||
} catch (e) { |
|
||||||
callback('Error encoding arguments: ' + e) |
|
||||||
return |
|
||||||
} |
|
||||||
if (!isConstructor || funArgs.length > 0) { |
|
||||||
try { |
|
||||||
data = helper.encodeParams(funAbi, funArgs) |
|
||||||
dataHex = data.toString('hex') |
|
||||||
} catch (e) { |
|
||||||
callback('Error encoding arguments: ' + e) |
|
||||||
return |
|
||||||
} |
|
||||||
} |
|
||||||
if (data.slice(0, 9) === 'undefined') { |
|
||||||
dataHex = data.slice(9) |
|
||||||
} |
|
||||||
if (data.slice(0, 2) === '0x') { |
|
||||||
dataHex = data.slice(2) |
|
||||||
} |
|
||||||
} |
|
||||||
var contractBytecode |
|
||||||
if (isConstructor) { |
|
||||||
contractBytecode = contract.evm.bytecode.object |
|
||||||
var bytecodeToDeploy = contract.evm.bytecode.object |
|
||||||
if (bytecodeToDeploy.indexOf('_') >= 0) { |
|
||||||
this.linkBytecode(contract, contracts, udapp, (err, bytecode) => { |
|
||||||
if (err) { |
|
||||||
callback('Error deploying required libraries: ' + err) |
|
||||||
} else { |
|
||||||
bytecodeToDeploy = bytecode + dataHex |
|
||||||
return callback(null, {dataHex: bytecodeToDeploy, funAbi, funArgs, contractBytecode, contractName: contractName}) |
|
||||||
} |
|
||||||
}, callbackStep) |
|
||||||
return |
|
||||||
} else { |
|
||||||
dataHex = bytecodeToDeploy + dataHex |
|
||||||
} |
|
||||||
} else { |
|
||||||
dataHex = Buffer.concat([helper.encodeFunctionId(funAbi), data]).toString('hex') |
|
||||||
} |
|
||||||
callback(null, { dataHex, funAbi, funArgs, contractBytecode, contractName: contractName }) |
|
||||||
}, |
|
||||||
|
|
||||||
atAddress: function () {}, |
|
||||||
|
|
||||||
linkBytecode: function (contract, contracts, udapp, callback, callbackStep) { |
|
||||||
if (contract.evm.bytecode.object.indexOf('_') < 0) { |
|
||||||
return callback(null, contract.evm.bytecode.object) |
|
||||||
} |
|
||||||
var libraryRefMatch = contract.evm.bytecode.object.match(/__([^_]{1,36})__/) |
|
||||||
if (!libraryRefMatch) { |
|
||||||
return callback('Invalid bytecode format.') |
|
||||||
} |
|
||||||
var libraryName = libraryRefMatch[1] |
|
||||||
// file_name:library_name
|
|
||||||
var libRef = libraryName.match(/(.*):(.*)/) |
|
||||||
if (!libRef) { |
|
||||||
return callback('Cannot extract library reference ' + libraryName) |
|
||||||
} |
|
||||||
if (!contracts[libRef[1]] || !contracts[libRef[1]][libRef[2]]) { |
|
||||||
return callback('Cannot find library reference ' + libraryName) |
|
||||||
} |
|
||||||
var libraryShortName = libRef[2] |
|
||||||
var library = contracts[libRef[1]][libraryShortName] |
|
||||||
if (!library) { |
|
||||||
return callback('Library ' + libraryName + ' not found.') |
|
||||||
} |
|
||||||
this.deployLibrary(libraryName, libraryShortName, library, contracts, udapp, (err, address) => { |
|
||||||
if (err) { |
|
||||||
return callback(err) |
|
||||||
} |
|
||||||
var hexAddress = address.toString('hex') |
|
||||||
if (hexAddress.slice(0, 2) === '0x') { |
|
||||||
hexAddress = hexAddress.slice(2) |
|
||||||
} |
|
||||||
contract.evm.bytecode.object = this.linkLibraryStandard(libraryShortName, hexAddress, contract) |
|
||||||
contract.evm.bytecode.object = this.linkLibrary(libraryName, hexAddress, contract.evm.bytecode.object) |
|
||||||
this.linkBytecode(contract, contracts, udapp, callback, callbackStep) |
|
||||||
}, callbackStep) |
|
||||||
}, |
|
||||||
|
|
||||||
deployLibrary: function (libraryName, libraryShortName, library, contracts, udapp, callback, callbackStep) { |
|
||||||
var address = library.address |
|
||||||
if (address) { |
|
||||||
return callback(null, address) |
|
||||||
} |
|
||||||
var bytecode = library.evm.bytecode.object |
|
||||||
if (bytecode.indexOf('_') >= 0) { |
|
||||||
this.linkBytecode(library, contracts, udapp, (err, bytecode) => { |
|
||||||
if (err) callback(err) |
|
||||||
else this.deployLibrary(libraryName, libraryShortName, library, contracts, udapp, callback, callbackStep) |
|
||||||
}, callbackStep) |
|
||||||
} else { |
|
||||||
callbackStep(`creation of library ${libraryName} pending...`) |
|
||||||
var data = {dataHex: bytecode, funAbi: {type: 'constructor'}, funArgs: [], contractBytecode: bytecode, contractName: libraryShortName} |
|
||||||
udapp.runTx({ data: data, useCall: false }, (err, txResult) => { |
|
||||||
if (err) { |
|
||||||
return callback(err) |
|
||||||
} |
|
||||||
var address = executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress |
|
||||||
library.address = address |
|
||||||
callback(err, address) |
|
||||||
}) |
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
linkLibraryStandardFromlinkReferences: function (libraryName, address, bytecode, linkReferences) { |
|
||||||
for (var file in linkReferences) { |
|
||||||
for (var libName in linkReferences[file]) { |
|
||||||
if (libraryName === libName) { |
|
||||||
bytecode = this.setLibraryAddress(address, bytecode, linkReferences[file][libName]) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return bytecode |
|
||||||
}, |
|
||||||
|
|
||||||
linkLibraryStandard: function (libraryName, address, contract) { |
|
||||||
return this.linkLibraryStandardFromlinkReferences(libraryName, address, contract.evm.bytecode.object, contract.evm.bytecode.linkReferences) |
|
||||||
}, |
|
||||||
|
|
||||||
setLibraryAddress: function (address, bytecodeToLink, positions) { |
|
||||||
if (positions) { |
|
||||||
for (var pos of positions) { |
|
||||||
var regpos = bytecodeToLink.match(new RegExp(`(.{${2 * pos.start}})(.{${2 * pos.length}})(.*)`)) |
|
||||||
if (regpos) { |
|
||||||
bytecodeToLink = regpos[1] + address + regpos[3] |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return bytecodeToLink |
|
||||||
}, |
|
||||||
|
|
||||||
linkLibrary: function (libraryName, address, bytecodeToLink) { |
|
||||||
var libLabel = '__' + libraryName + Array(39 - libraryName.length).join('_') |
|
||||||
if (bytecodeToLink.indexOf(libLabel) === -1) return bytecodeToLink |
|
||||||
|
|
||||||
address = Array(40 - address.length + 1).join('0') + address |
|
||||||
while (bytecodeToLink.indexOf(libLabel) >= 0) { |
|
||||||
bytecodeToLink = bytecodeToLink.replace(libLabel, address) |
|
||||||
} |
|
||||||
return bytecodeToLink |
|
||||||
}, |
|
||||||
|
|
||||||
decodeResponseToTreeView: function (response, fnabi) { |
|
||||||
var treeView = new TreeView({ |
|
||||||
extractData: (item, parent, key) => { |
|
||||||
var ret = {} |
|
||||||
if (BN.isBN(item)) { |
|
||||||
ret.self = item.toString(10) |
|
||||||
ret.children = [] |
|
||||||
} else { |
|
||||||
ret = treeView.extractDataDefault(item, parent, key) |
|
||||||
} |
|
||||||
return ret |
|
||||||
} |
|
||||||
}) |
|
||||||
return treeView.render(this.decodeResponse(response, fnabi)) |
|
||||||
}, |
|
||||||
|
|
||||||
decodeResponse: function (response, fnabi) { |
|
||||||
// Only decode if there supposed to be fields
|
|
||||||
if (fnabi.outputs && fnabi.outputs.length > 0) { |
|
||||||
try { |
|
||||||
var i |
|
||||||
|
|
||||||
var outputTypes = [] |
|
||||||
for (i = 0; i < fnabi.outputs.length; i++) { |
|
||||||
outputTypes.push(fnabi.outputs[i].type) |
|
||||||
} |
|
||||||
|
|
||||||
// decode data
|
|
||||||
var decodedObj = ethJSABI.rawDecode(outputTypes, response) |
|
||||||
|
|
||||||
// format decoded data
|
|
||||||
decodedObj = ethJSABI.stringify(outputTypes, decodedObj) |
|
||||||
var json = {} |
|
||||||
for (i = 0; i < outputTypes.length; i++) { |
|
||||||
var name = fnabi.outputs[i].name |
|
||||||
json[i] = outputTypes[i] + ': ' + (name ? name + ' ' + decodedObj[i] : decodedObj[i]) |
|
||||||
} |
|
||||||
|
|
||||||
return json |
|
||||||
} catch (e) { |
|
||||||
return { error: 'Failed to decode output: ' + e } |
|
||||||
} |
|
||||||
} |
|
||||||
return {} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,23 @@ |
|||||||
|
var TreeView = require('remix-debugger').ui.TreeView |
||||||
|
var ethJSUtil = require('ethereumjs-util') |
||||||
|
var BN = ethJSUtil.BN |
||||||
|
var remixLib = require('remix-lib') |
||||||
|
var txFormat = remixLib.execution.txFormat |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
decodeResponseToTreeView: function (response, fnabi) { |
||||||
|
var treeView = new TreeView({ |
||||||
|
extractData: (item, parent, key) => { |
||||||
|
var ret = {} |
||||||
|
if (BN.isBN(item)) { |
||||||
|
ret.self = item.toString(10) |
||||||
|
ret.children = [] |
||||||
|
} else { |
||||||
|
ret = treeView.extractDataDefault(item, parent, key) |
||||||
|
} |
||||||
|
return ret |
||||||
|
} |
||||||
|
}) |
||||||
|
return treeView.render(txFormat.decodeResponse(response, fnabi)) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue