Commit 9f160f01 authored by yann300's avatar yann300

jsonio solidity

parent a2d85a9c
...@@ -5,6 +5,8 @@ var solc = require('solc/wrapper') ...@@ -5,6 +5,8 @@ var solc = require('solc/wrapper')
var soljson = require('../soljson') var soljson = require('../soljson')
var compiler = solc(soljson) var compiler = solc(soljson)
var compilerInput = require('../src/app/compiler/compiler-input')
gatherCompilationResults(function (error, data) { gatherCompilationResults(function (error, data) {
if (error) { if (error) {
console.log(error) console.log(error)
...@@ -44,20 +46,16 @@ function gatherCompilationResults (callback) { ...@@ -44,20 +46,16 @@ function gatherCompilationResults (callback) {
function compile (source, optimization, addCompilationResult) { function compile (source, optimization, addCompilationResult) {
var missingInputs = [] var missingInputs = []
try { try {
var result = compiler.compile(source, optimization, function (path) { var input = compilerInput(source, {optimize: optimization})
var result = compiler.compileStandardWrapper(input, function (path) {
missingInputs.push(path) missingInputs.push(path)
return { error: 'Deferred import' }
}) })
input = input.replace(/(\t)|(\n)|(\\n)|( )/g, '')
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
var key = optimization.toString()
for (var k in source.sources) {
key += k + source.sources[k]
}
key = key.replace(/(\t)|(\n)|( )/g, '')
var ret = { var ret = {
key: key, key: input,
source: source, source: source,
optimization: optimization, optimization: optimization,
missingInputs: missingInputs, missingInputs: missingInputs,
......
...@@ -297,6 +297,9 @@ function run () { ...@@ -297,6 +297,9 @@ function run () {
getCurrentFile: () => { getCurrentFile: () => {
return config.get('currentFile') return config.get('currentFile')
}, },
getSourceName: (index) => {
return compiler.getSourceName(index)
},
highlight: (position, node) => { highlight: (position, node) => {
if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) { if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) {
var lineColumn = offsetToLineColumnConverter.offsetToLineColumn(position, position.file, compiler.lastCompilationResult) var lineColumn = offsetToLineColumnConverter.offsetToLineColumn(position, position.file, compiler.lastCompilationResult)
...@@ -315,7 +318,10 @@ function run () { ...@@ -315,7 +318,10 @@ function run () {
} }
} }
} }
return editor.addMarker(lineColumn, compiler.lastCompilationResult.data.sourceList[position.file], css) var fileName = compiler.getSourceName(position.file)
if (fileName) {
return editor.addMarker(lineColumn, fileName, css)
}
} }
return null return null
}, },
...@@ -333,7 +339,7 @@ function run () { ...@@ -333,7 +339,7 @@ function run () {
jumpTo: (position) => { jumpTo: (position) => {
if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) { if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) {
var lineColumn = offsetToLineColumnConverter.offsetToLineColumn(position, position.file, compiler.lastCompilationResult) var lineColumn = offsetToLineColumnConverter.offsetToLineColumn(position, position.file, compiler.lastCompilationResult)
var filename = compiler.lastCompilationResult.data.sourceList[position.file] var filename = compiler.getSourceName(position.file)
if (filename !== config.get('currentFile') && (filesProviders['browser'].exists(filename) || filesProviders['localhost'].exists(filename))) { if (filename !== config.get('currentFile') && (filesProviders['browser'].exists(filename) || filesProviders['localhost'].exists(filename))) {
fileManager.switchFile(filename) fileManager.switchFile(filename)
} }
...@@ -493,7 +499,7 @@ function run () { ...@@ -493,7 +499,7 @@ function run () {
var staticAnalysisAPI = { var staticAnalysisAPI = {
renderWarning: (label, warningContainer, type) => { renderWarning: (label, warningContainer, type) => {
return renderer.error(label, warningContainer, type) return renderer.error({ severity: 'warning', formattedMessage: label }, warningContainer, type)
}, },
offsetToLineColumn: (location, file) => { offsetToLineColumn: (location, file) => {
return offsetToLineColumnConverter.offsetToLineColumn(location, file, compiler.lastCompilationResult) return offsetToLineColumnConverter.offsetToLineColumn(location, file, compiler.lastCompilationResult)
...@@ -511,11 +517,17 @@ function run () { ...@@ -511,11 +517,17 @@ function run () {
document.querySelector(`.${css.dragbar2}`).style.right = delta + 'px' document.querySelector(`.${css.dragbar2}`).style.right = delta + 'px'
onResize() onResize()
}, },
getSource: (fileName) => {
return compiler.getSource(fileName)
},
getContracts: () => { getContracts: () => {
if (compiler.lastCompilationResult && compiler.lastCompilationResult.data) { return compiler.getContracts()
return compiler.lastCompilationResult.data.contracts },
} getContract: (name) => {
return null return compiler.getContract(name)
},
visitContracts: (cb) => {
compiler.visitContracts(cb)
}, },
udapp: () => { udapp: () => {
return udapp return udapp
...@@ -595,7 +607,7 @@ function run () { ...@@ -595,7 +607,7 @@ function run () {
this.fullLineMarker = null this.fullLineMarker = null
this.source = null this.source = null
if (lineColumnPos) { if (lineColumnPos) {
this.source = compiler.lastCompilationResult.data.sourceList[location.file] // auto switch to that tab this.source = compiler.getSourceName(location.file)
if (config.get('currentFile') !== this.source) { if (config.get('currentFile') !== this.source) {
fileManager.switchFile(this.source) fileManager.switchFile(this.source)
} }
...@@ -664,7 +676,7 @@ function run () { ...@@ -664,7 +676,7 @@ function run () {
if (error) { if (error) {
console.log(error) console.log(error)
} else { } else {
sources[target] = content sources[target] = { content }
compiler.compile(sources, target) compiler.compile(sources, target)
} }
}) })
......
'use strict'
/*
opts:
- optimize
- { file_name: { library_name: address } }
*/
module.exports = (sources, opts) => {
return JSON.stringify({
target: opts.target,
language: 'Solidity',
sources: sources,
settings: {
optimizer: {
enabled: opts.optimize === true,
runs: 500
}
},
libraries: opts.libraries,
outputSelection: {
'*': {
'*': [ 'metadata', 'evm.bytecode', 'evm.deployedBytecode', 'abi', 'legacyAST', 'metadata', 'evm.assembly', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
}
}
})
}
'use strict' 'use strict'
var solc = require('solc/wrapper') var solc = require('solc/wrapper')
var compilerInput = require('./compiler-input')
var compileJSON = function () { return '' } var compileJSON = function () { return '' }
var missingInputs = [] var missingInputs = []
...@@ -22,10 +23,12 @@ module.exports = function (self) { ...@@ -22,10 +23,12 @@ module.exports = function (self) {
compileJSON = function (input, optimize) { compileJSON = function (input, optimize) {
try { try {
return JSON.stringify(compiler.compile(JSON.parse(input), optimize, function (path) { input = JSON.parse(input)
var inputStandard = compilerInput(input.sources, {optimize: optimize, target: input.target})
return compiler.compileStandardWrapper(inputStandard, function (path) {
missingInputs.push(path) missingInputs.push(path)
return { 'error': 'Deferred import' } return { 'error': 'Deferred import' }
})) })
} catch (exception) { } catch (exception) {
return JSON.stringify({ error: 'Uncaught JavaScript exception:\n' + exception }) return JSON.stringify({ error: 'Uncaught JavaScript exception:\n' + exception })
} }
......
...@@ -4,10 +4,13 @@ var solc = require('solc/wrapper') ...@@ -4,10 +4,13 @@ var solc = require('solc/wrapper')
var solcABI = require('solc/abi') var solcABI = require('solc/abi')
var webworkify = require('webworkify') var webworkify = require('webworkify')
var utils = require('../../lib/utils')
var compilerInput = require('./compiler-input')
var EventManager = require('ethereum-remix').lib.EventManager var EventManager = require('ethereum-remix').lib.EventManager
var txHelper = require('../execution/txHelper')
/* /*
trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration
*/ */
...@@ -44,7 +47,7 @@ function Compiler (handleImportCall) { ...@@ -44,7 +47,7 @@ function Compiler (handleImportCall) {
gatherImports(files, target, missingInputs, function (error, input) { gatherImports(files, target, missingInputs, function (error, input) {
if (error) { if (error) {
self.lastCompilationResult = null self.lastCompilationResult = null
self.event.trigger('compilationFinished', [false, { 'error': error }, files]) self.event.trigger('compilationFinished', [false, {'error': { formattedMessage: error, severity: 'error' }}, files])
} else { } else {
compileJSON(input, optimize ? 1 : 0) compileJSON(input, optimize ? 1 : 0)
} }
...@@ -82,7 +85,9 @@ function Compiler (handleImportCall) { ...@@ -82,7 +85,9 @@ function Compiler (handleImportCall) {
var result var result
try { try {
result = compiler.compile(source, optimize, missingInputsCallback) var input = compilerInput(source.sources, {optimize: optimize, target: source.target})
result = compiler.compileStandardWrapper(input, missingInputsCallback)
result = JSON.parse(result)
} catch (exception) { } catch (exception) {
result = { error: 'Uncaught JavaScript exception:\n' + exception } result = { error: 'Uncaught JavaScript exception:\n' + exception }
} }
...@@ -97,17 +102,86 @@ function Compiler (handleImportCall) { ...@@ -97,17 +102,86 @@ function Compiler (handleImportCall) {
data: null, data: null,
source: null source: null
} }
/**
* return the contract obj of the given @arg name. Uses last compilation result.
* return null if not found
* @param {String} name - contract name
* @returns contract obj and associated file: { contract, file } or null
*/
this.getContract = (name) => {
if (this.lastCompilationResult.data && this.lastCompilationResult.data.contracts) {
return txHelper.getContract(name, this.lastCompilationResult.data.contracts)
}
return null
}
/**
* call the given @arg cb (function) for all the contracts. Uses last compilation result
* @param {Function} cb - callback
*/
this.visitContracts = (cb) => {
if (this.lastCompilationResult.data && this.lastCompilationResult.data.contracts) {
return txHelper.visitContracts(this.lastCompilationResult.data.contracts, cb)
}
return null
}
/**
* return the compiled contracts from the last compilation result
* @return {Object} - contracts
*/
this.getContracts = () => {
if (this.lastCompilationResult.data && this.lastCompilationResult.data.contracts) {
return this.lastCompilationResult.data.contracts
}
return null
}
/**
* return the sources from the last compilation result
* @param {Object} cb - map of sources
*/
this.getSources = () => {
if (this.lastCompilationResult.source) {
return this.lastCompilationResult.source.sources
}
return null
}
/**
* return the sources @arg fileName from the last compilation result
* @param {Object} cb - map of sources
*/
this.getSource = (fileName) => {
if (this.lastCompilationResult.source) {
return this.lastCompilationResult.source.sources[fileName]
}
return null
}
/**
* return the source from the last compilation result that has the given index. null if source not found
* @param {Int} index - index of the source
*/
this.getSourceName = (index) => {
if (this.lastCompilationResult.data && this.lastCompilationResult.data.sources) {
return Object.keys(this.lastCompilationResult.data.sources)[index]
}
return null
}
function compilationFinished (data, missingInputs, source) { function compilationFinished (data, missingInputs, source) {
var noFatalErrors = true // ie warnings are ok var noFatalErrors = true // ie warnings are ok
function isValidError (error) { function isValidError (error) {
// The deferred import is not a real error // The deferred import is not a real error
// FIXME: maybe have a better check? // FIXME: maybe have a better check?
if (/Deferred import/.exec(error)) { if (/Deferred import/.exec(error.message)) {
return false return false
} }
return utils.errortype(error) !== 'warning' return error.severity !== 'warning'
} }
if (data['error'] !== undefined) { if (data['error'] !== undefined) {
...@@ -233,7 +307,7 @@ function Compiler (handleImportCall) { ...@@ -233,7 +307,7 @@ function Compiler (handleImportCall) {
for (var fileName in files) { for (var fileName in files) {
var match var match
while ((match = importRegex.exec(files[fileName]))) { while ((match = importRegex.exec(files[fileName].content))) {
var importFilePath = match[1] var importFilePath = match[1]
if (importFilePath.startsWith('./')) { if (importFilePath.startsWith('./')) {
var path = /(.*\/).*/.exec(target) var path = /(.*\/).*/.exec(target)
...@@ -261,7 +335,7 @@ function Compiler (handleImportCall) { ...@@ -261,7 +335,7 @@ function Compiler (handleImportCall) {
if (err) { if (err) {
cb(err) cb(err)
} else { } else {
files[m] = content files[m] = { content }
gatherImports(files, target, importHints, cb) gatherImports(files, target, importHints, cb)
} }
}) })
...@@ -281,12 +355,9 @@ function Compiler (handleImportCall) { ...@@ -281,12 +355,9 @@ function Compiler (handleImportCall) {
} }
function updateInterface (data) { function updateInterface (data) {
for (var contract in data.contracts) { txHelper.visitContracts(data.contracts, (contract) => {
var abi = JSON.parse(data.contracts[contract].interface) data.contracts[contract.file][contract.name].abi = solcABI.update(truncateVersion(currentVersion), contract.object.abi)
abi = solcABI.update(truncateVersion(currentVersion), abi) })
data.contracts[contract].interface = JSON.stringify(abi)
}
return data return data
} }
} }
......
...@@ -11,39 +11,35 @@ var getDetails = function (contractName, contract, source) { ...@@ -11,39 +11,35 @@ var getDetails = function (contractName, contract, source) {
var detail = {} var detail = {}
detail.name = contractName detail.name = contractName
detail.metadata = contract.metadata detail.metadata = contract.metadata
if (contract.bytecode) { if (contract.evm.bytecode.object) {
detail.bytecode = contract.bytecode detail.bytecode = contract.evm.bytecode.object
} }
detail.interface = contract.interface detail.abi = contract.abi
if (contract.bytecode) { if (contract.evm.bytecode.object) {
detail.bytecode = contract.bytecode detail.bytecode = contract.evm.bytecode
detail.web3Deploy = gethDeploy(contractName.toLowerCase(), contract['interface'], contract.bytecode) detail.web3Deploy = gethDeploy(contractName.toLowerCase(), contract.abi, contract.evm.bytecode.object)
detail.metadataHash = retrieveMetadataHash(contract.bytecode) detail.metadataHash = retrieveMetadataHash(contract.evm.bytecode.object)
if (detail.metadataHash) { if (detail.metadataHash) {
detail.swarmLocation = 'bzzr://' + detail.metadataHash detail.swarmLocation = 'bzzr://' + detail.metadataHash
} }
} }
detail.functionHashes = {} detail.functionHashes = {}
for (var fun in contract.functionHashes) { for (var fun in contract.evm.methodIdentifiers) {
detail.functionHashes[contract.functionHashes[fun]] = fun detail.functionHashes[contract.evm.methodIdentifiers[fun]] = fun
} }
detail.gasEstimates = formatGasEstimates(contract.gasEstimates) detail.gasEstimates = formatGasEstimates(contract.evm.gasEstimates)
if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0) { if (contract.evm.deployedBytecode && contract.evm.deployedBytecode.object.length > 0) {
detail['Runtime Bytecode'] = contract.runtimeBytecode detail['Runtime Bytecode'] = contract.evm.deployedBytecode
}
if (contract.opcodes !== undefined && contract.opcodes !== '') {
detail['Opcodes'] = contract.opcodes
} }
if (contract.assembly !== null) { if (contract.assembly !== null) {
detail['Assembly'] = formatAssemblyText(contract.assembly, '', source) detail['Assembly'] = formatAssemblyText(contract.evm.legacyAssembly, '', source.content)
} }
return detail return detail
...@@ -87,14 +83,14 @@ var formatAssemblyText = function (asm, prefix, source) { ...@@ -87,14 +83,14 @@ var formatAssemblyText = function (asm, prefix, source) {
var gethDeploy = function (contractName, jsonInterface, bytecode) { var gethDeploy = function (contractName, jsonInterface, bytecode) {
var code = '' var code = ''
var funABI = txHelper.getConstructorInterface(JSON.parse(jsonInterface)) var funABI = txHelper.getConstructorInterface(jsonInterface)
funABI.inputs.forEach(function (inp) { funABI.inputs.forEach(function (inp) {
code += 'var ' + inp.name + ' = /* var of type ' + inp.type + ' here */ ;\n' code += 'var ' + inp.name + ' = /* var of type ' + inp.type + ' here */ ;\n'
}) })
contractName = contractName.replace(/[:./]/g, '_') contractName = contractName.replace(/[:./]/g, '_')
code += 'var ' + contractName + 'Contract = web3.eth.contract(' + jsonInterface.replace('\n', '') + ');' + code += 'var ' + contractName + 'Contract = web3.eth.contract(' + JSON.stringify(jsonInterface).replace('\n', '') + ');' +
'\nvar ' + contractName + ' = ' + contractName + 'Contract.new(' '\nvar ' + contractName + ' = ' + contractName + 'Contract.new('
funABI.inputs.forEach(function (inp) { funABI.inputs.forEach(function (inp) {
...@@ -116,10 +112,8 @@ var gethDeploy = function (contractName, jsonInterface, bytecode) { ...@@ -116,10 +112,8 @@ var gethDeploy = function (contractName, jsonInterface, bytecode) {
} }
var formatGasEstimates = function (data) { var formatGasEstimates = function (data) {
// FIXME: the whole gasEstimates object should be nil instead if (!data) return {}
if (data.creation === undefined && data.external === undefined && data.internal === undefined) { if (data.creation === undefined && data.external === undefined && data.internal === undefined) return {}
return
}
var gasToText = function (g) { var gasToText = function (g) {
return g === null ? 'unknown' : g return g === null ? 'unknown' : g
...@@ -128,7 +122,7 @@ var formatGasEstimates = function (data) { ...@@ -128,7 +122,7 @@ var formatGasEstimates = function (data) {
var ret = {} var ret = {}
var fun var fun
if ('creation' in data) { if ('creation' in data) {
ret['Creation'] = gasToText(data.creation[0]) + ' + ' + gasToText(data.creation[1]) + '\n' ret['Creation'] = data.creation
} }
if ('external' in data) { if ('external' in data) {
......
...@@ -82,7 +82,7 @@ class ContextualListener { ...@@ -82,7 +82,7 @@ class ContextualListener {
return true return true
} }
for (var s in compilationResult.sources) { for (var s in compilationResult.sources) {
this.astWalker.walk(compilationResult.sources[s].AST, callback) this.astWalker.walk(compilationResult.sources[s].legacyAST, callback)
} }
} }
} }
...@@ -92,7 +92,7 @@ class ContextualListener { ...@@ -92,7 +92,7 @@ class ContextualListener {
var position = this.sourceMappingDecoder.decode(node.src) var position = this.sourceMappingDecoder.decode(node.src)
var eventId = this._api.highlight(position, node) var eventId = this._api.highlight(position, node)
if (eventId) { if (eventId) {
this._activeHighlights.push({ eventId, position, fileTarget: compilationResult.data.sourceList[position.file] }) this._activeHighlights.push({ eventId, position, fileTarget: this._api.getSourceName(position.file) })
} }
} }
......
'use strict' 'use strict'
var ethJSABI = require('ethereumjs-abi') var ethJSABI = require('ethereumjs-abi')
var txHelper = require('../execution/txHelper')
/** /**
* Register to txListener and extract events * Register to txListener and extract events
...@@ -35,10 +36,9 @@ class EventsDecoder { ...@@ -35,10 +36,9 @@ class EventsDecoder {
this._decodeEvents(tx, receipt.logs, contract, contracts, cb) this._decodeEvents(tx, receipt.logs, contract, contracts, cb)
} }
_eventABI (contractabi) { _eventABI (contract) {
contractabi = JSON.parse(contractabi.interface)
var eventABI = {} var eventABI = {}
contractabi.forEach(function (funABI, i) { contract.abi.forEach(function (funABI, i) {
if (funABI.type !== 'event') { if (funABI.type !== 'event') {
return return
} }
...@@ -50,9 +50,9 @@ class EventsDecoder { ...@@ -50,9 +50,9 @@ class EventsDecoder {
_eventsABI (compiledContracts) { _eventsABI (compiledContracts) {
var eventsABI = {} var eventsABI = {}
for (var contract in compiledContracts) { txHelper.visitContracts(compiledContracts, (contract) => {
eventsABI[contract] = this._eventABI(compiledContracts[contract]) eventsABI[contract.name] = this._eventABI(contract.object)
} })
return eventsABI return eventsABI
} }
......
...@@ -46,7 +46,7 @@ module.exports = { ...@@ -46,7 +46,7 @@ module.exports = {
dataHex = data.slice(2) dataHex = data.slice(2)
} }
if (isConstructor) { if (isConstructor) {
var bytecodeToDeploy = contract.bytecode var bytecodeToDeploy = contract.evm.bytecode.object
if (bytecodeToDeploy.indexOf('_') >= 0) { if (bytecodeToDeploy.indexOf('_') >= 0) {
this.linkBytecode(contract, contracts, udapp, (err, bytecode) => { this.linkBytecode(contract, contracts, udapp, (err, bytecode) => {
if (err) { if (err) {
...@@ -69,47 +69,51 @@ module.exports = { ...@@ -69,47 +69,51 @@ module.exports = {
atAddress: function () {}, atAddress: function () {},
linkBytecode: function (contract, contracts, udapp, callback, callbackStep) { linkBytecode: function (contract, contracts, udapp, callback, callbackStep) {
var bytecode = contract.bytecode if (contract.evm.bytecode.object.indexOf('_') < 0) {
if (bytecode.indexOf('_') < 0) { return callback(null, contract.evm.bytecode.object)
return callback(null, bytecode)
} }
var libraryRefMatch = bytecode.match(/__([^_]{1,36})__/) var libraryRefMatch = contract.evm.bytecode.object.match(/__([^_]{1,36})__/)
if (!libraryRefMatch) { if (!libraryRefMatch) {
return callback('Invalid bytecode format.') return callback('Invalid bytecode format.')
} }
var libraryName = libraryRefMatch[1] var libraryName = libraryRefMatch[1]
var libraryabi = helper.getContractByName(libraryName, contracts) // file_name:library_name
if (!libraryabi) { 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.') return callback('Library ' + libraryName + ' not found.')
} }
this.deployLibrary(libraryName, libraryabi, udapp, (err, address) => { this.deployLibrary(libraryName, library, contracts, udapp, (err, address) => {
if (err) { if (err) {
return callback(err) return callback(err)
} }
var libLabel = '__' + libraryName + Array(39 - libraryName.length).join('_')
var hexAddress = address.toString('hex') var hexAddress = address.toString('hex')
if (hexAddress.slice(0, 2) === '0x') { if (hexAddress.slice(0, 2) === '0x') {
hexAddress = hexAddress.slice(2) hexAddress = hexAddress.slice(2)
} }
hexAddress = Array(40 - hexAddress.length + 1).join('0') + hexAddress contract.evm.bytecode.object = this.linkLibraryStandard(libraryShortName, hexAddress, contract)
while (bytecode.indexOf(libLabel) >= 0) { contract.evm.bytecode.object = this.linkLibrary(libraryName, hexAddress, contract.evm.bytecode.object)
bytecode = bytecode.replace(libLabel, hexAddress)
}
contract.bytecode = bytecode
this.linkBytecode(contract, contracts, udapp, callback, callbackStep) this.linkBytecode(contract, contracts, udapp, callback, callbackStep)
}, callbackStep) }, callbackStep)
}, },
deployLibrary: function (libraryName, library, udapp, callback, callbackStep) { deployLibrary: function (libraryName, library, contracts, udapp, callback, callbackStep) {
var address = library.address var address = library.address
if (address) { if (address) {
return callback(null, address) return callback(null, address)
} }
var bytecode = library.bytecode var bytecode = library.evm.bytecode.object
if (bytecode.indexOf('_') >= 0) { if (bytecode.indexOf('_') >= 0) {
this.linkBytecode(libraryName, library, udapp, (err, bytecode) => { this.linkBytecode(libraryName, contracts, udapp, (err, bytecode) => {
if (err) callback(err) if (err) callback(err)
else this.deployLibrary(libraryName, library, udapp, callback, callbackStep) else this.deployLibrary(libraryName, library, contracts, udapp, callback, callbackStep)
}, callbackStep) }, callbackStep)
} else { } else {
callbackStep(`creation of library ${libraryName} pending...`) callbackStep(`creation of library ${libraryName} pending...`)
...@@ -124,6 +128,41 @@ module.exports = { ...@@ -124,6 +128,41 @@ module.exports = {
} }
}, },
linkLibraryStandard: function (libraryName, address, contract) {
var bytecode = contract.evm.bytecode.object
for (var file in contract.evm.bytecode.linkReferences) {
for (var libName in contract.evm.bytecode.linkReferences[file]) {
if (libraryName === libName) {
bytecode = this.setLibraryAddress(address, bytecode, contract.evm.bytecode.linkReferences[file][libName])
}
}
}
return bytecode
},
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) { decodeResponseToTreeView: function (response, fnabi) {
var treeView = new TreeView({ var treeView = new TreeView({
extractData: (item, parent, key) => { extractData: (item, parent, key) => {
......
...@@ -32,7 +32,7 @@ module.exports = { ...@@ -32,7 +32,7 @@ module.exports = {
}, },
sortAbiFunction: function (contract) { sortAbiFunction: function (contract) {
var abi = JSON.parse(contract.interface).sort(function (a, b) { var abi = contract.abi.sort(function (a, b) {
if (a.name > b.name) { if (a.name > b.name) {
return -1 return -1
} else { } else {
...@@ -86,15 +86,34 @@ module.exports = { ...@@ -86,15 +86,34 @@ module.exports = {
} }
}, },
getContractByName: function (contractName, contracts) { /**
for (var c in contracts) { * return the contract obj of the given @arg name. Uses last compilation result.
if (c === contractName) { * return null if not found
return contracts[c] * @param {String} name - contract name
* @returns contract obj and associated file: { contract, file } or null
*/
getContract: (contractName, contracts) => {
for (var file in contracts) {
if (contracts[file][contractName]) {
return { object: contracts[file][contractName], file: file }
} }
} }
return null return null
}, },
/**
* call the given @arg cb (function) for all the contracts. Uses last compilation result
* stop visiting when cb return true
* @param {Function} cb - callback
*/
visitContracts: (contracts, cb) => {
for (var file in contracts) {
for (var name in contracts[file]) {
if (cb({ name: name, object: contracts[file][name], file: file })) return
}
}
},
inputParametersDeclarationToString: function (abiinputs) { inputParametersDeclarationToString: function (abiinputs) {
var inputs = '' var inputs = ''
if (abiinputs) { if (abiinputs) {
......
...@@ -7,6 +7,7 @@ var remix = require('ethereum-remix') ...@@ -7,6 +7,7 @@ var remix = require('ethereum-remix')
var codeUtil = remix.util.code var codeUtil = remix.util.code
var executionContext = require('../../execution-context') var executionContext = require('../../execution-context')
var txFormat = require('./txFormat') var txFormat = require('./txFormat')
var txHelper = require('./txHelper')
/** /**
* poll web3 each 2s if web3 * poll web3 each 2s if web3
...@@ -222,7 +223,7 @@ class TxListener { ...@@ -222,7 +223,7 @@ class TxListener {
// if web3: we have to call getTransactionReceipt to get the created address // if web3: we have to call getTransactionReceipt to get the created address
// if VM: created address already included // if VM: created address already included
var code = tx.input var code = tx.input
contractName = this._tryResolveContract(code, contracts, 'bytecode') contractName = this._tryResolveContract(code, contracts, true)
if (contractName) { if (contractName) {
this._api.resolveReceipt(tx, (error, receipt) => { this._api.resolveReceipt(tx, (error, receipt) => {
if (error) return cb(error) if (error) return cb(error)
...@@ -244,7 +245,7 @@ class TxListener { ...@@ -244,7 +245,7 @@ class TxListener {
executionContext.web3().eth.getCode(tx.to, (error, code) => { executionContext.web3().eth.getCode(tx.to, (error, code) => {
if (error) return cb(error) if (error) return cb(error)
if (code) { if (code) {
var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode') var contractName = this._tryResolveContract(code, contracts, false)
if (contractName) { if (contractName) {
this._resolvedContracts[tx.to] = contractName this._resolvedContracts[tx.to] = contractName
var fun = this._resolveFunction(contractName, contracts, tx, false) var fun = this._resolveFunction(contractName, contracts, tx, false)
...@@ -264,11 +265,17 @@ class TxListener { ...@@ -264,11 +265,17 @@ class TxListener {
} }
_resolveFunction (contractName, compiledContracts, tx, isCtor) { _resolveFunction (contractName, compiledContracts, tx, isCtor) {
var abi = JSON.parse(compiledContracts[contractName].interface) var contract = txHelper.getContract(contractName, compiledContracts)
if (!contract) {
console.log('txListener: cannot resolve ' + contractName)
return
}
var abi = contract.object.abi
var inputData = tx.input.replace('0x', '') var inputData = tx.input.replace('0x', '')
if (!isCtor) { if (!isCtor) {
for (var fn in compiledContracts[contractName].functionHashes) { var methodIdentifiers = contract.object.evm.methodIdentifiers
if (compiledContracts[contractName].functionHashes[fn] === inputData.substring(0, 8)) { for (var fn in methodIdentifiers) {
if (methodIdentifiers[fn] === inputData.substring(0, 8)) {
var fnabi = getFunction(abi, fn) var fnabi = getFunction(abi, fn)
this._resolvedTransactions[tx.hash] = { this._resolvedTransactions[tx.hash] = {
contractName: contractName, contractName: contractName,
...@@ -290,7 +297,7 @@ class TxListener { ...@@ -290,7 +297,7 @@ class TxListener {
params: null params: null
} }
} else { } else {
var bytecode = compiledContracts[contractName].bytecode var bytecode = contract.object.evm.bytecode.object
var params = null var params = null
if (bytecode && bytecode.length) { if (bytecode && bytecode.length) {
params = this._decodeInputParams(inputData.substring(bytecode.length), getConstructorInterface(abi)) params = this._decodeInputParams(inputData.substring(bytecode.length), getConstructorInterface(abi))
...@@ -305,13 +312,16 @@ class TxListener { ...@@ -305,13 +312,16 @@ class TxListener {
return this._resolvedTransactions[tx.hash] return this._resolvedTransactions[tx.hash]
} }
_tryResolveContract (codeToResolve, compiledContracts, type) { _tryResolveContract (codeToResolve, compiledContracts, isCreation) {
for (var k in compiledContracts) { var found = null
if (codeUtil.compareByteCode(codeToResolve, '0x' + compiledContracts[k][type])) { txHelper.visitContracts(compiledContracts, (contract) => {
return k var bytes = isCreation ? contract.object.evm.bytecode.object : contract.object.evm.deployedBytecode.object
} if (codeUtil.compareByteCode(codeToResolve, '0x' + bytes)) {
found = contract.name
return true
} }
return null })
return found
} }
_decodeInputParams (data, abi) { _decodeInputParams (data, abi) {
......
...@@ -2,46 +2,46 @@ var name = 'Gas costs: ' ...@@ -2,46 +2,46 @@ var name = 'Gas costs: '
var desc = 'Warn if the gas requirements of functions are too high.' var desc = 'Warn if the gas requirements of functions are too high.'
var categories = require('./categories') var categories = require('./categories')
var yo = require('yo-yo') var yo = require('yo-yo')
var txHelper = require('../../execution/txHelper')
function gasCosts () { function gasCosts () {
} }
gasCosts.prototype.report = function (compilationResults) { gasCosts.prototype.report = function (compilationResults) {
var report = [] var report = []
for (var contractName in compilationResults.contracts) { txHelper.visitContracts(compilationResults.contracts, (contract) => {
var contract = compilationResults.contracts[contractName]
if ( if (
contract.gasEstimates === undefined || !contract.object.evm.gasEstimates ||
contract.gasEstimates.external === undefined !contract.object.evm.gasEstimates.external
) { ) {
continue return
} }
var fallback = contract.gasEstimates.external[''] var fallback = contract.object.evm.gasEstimates.external['']
if (fallback !== undefined) { if (fallback !== undefined) {
if (fallback === null || fallback >= 2100) { if (fallback === null || fallback >= 2100 || fallback === 'infinite') {
report.push({ report.push({
warning: yo`<span>Fallback function of contract ${contractName} requires too much gas (${fallback}).<br /> warning: yo`<span>Fallback function of contract ${contract.name} requires too much gas (${fallback}).<br />
If the fallback function requires more than 2300 gas, the contract cannot receive Ether.</span>` If the fallback function requires more than 2300 gas, the contract cannot receive Ether.</span>`
}) })
} }
} }
for (var functionName in contract.gasEstimates.external) { for (var functionName in contract.object.evm.gasEstimates.external) {
if (functionName === '') { if (functionName === '') {
continue continue
} }
var gas = contract.gasEstimates.external[functionName] var gas = contract.object.evm.gasEstimates.external[functionName]
var gasString = gas === null ? 'unknown or not constant' : 'high: ' + gas var gasString = gas === null ? 'unknown or not constant' : 'high: ' + gas
if (gas === null || gas >= 3000000) { if (gas === null || gas >= 3000000 || gas === 'infinite') {
report.push({ report.push({
warning: yo`<span>Gas requirement of function ${contractName}.${functionName} ${gasString}.<br /> warning: yo`<span>Gas requirement of function ${contract.name}.${functionName} ${gasString}.<br />
If the gas requirement of a function is higher than the block gas limit, it cannot be executed. If the gas requirement of a function is higher than the block gas limit, it cannot be executed.
Please avoid loops in your functions or actions that modify large areas of storage Please avoid loops in your functions or actions that modify large areas of storage
(this includes clearing or copying arrays in storage)</span>` (this includes clearing or copying arrays in storage)</span>`
}) })
} }
} }
} })
return report return report
} }
......
...@@ -19,7 +19,7 @@ staticAnalysisRunner.prototype.runWithModuleList = function (compilationResult, ...@@ -19,7 +19,7 @@ staticAnalysisRunner.prototype.runWithModuleList = function (compilationResult,
// Also provide convenience analysis via the AST walker. // Also provide convenience analysis via the AST walker.
var walker = new AstWalker() var walker = new AstWalker()
for (var k in compilationResult.sources) { for (var k in compilationResult.sources) {
walker.walk(compilationResult.sources[k].AST, {'*': function (node) { walker.walk(compilationResult.sources[k].legacyAST, {'*': function (node) {
modules.map(function (item, i) { modules.map(function (item, i) {
if (item.mod.visit !== undefined) { if (item.mod.visit !== undefined) {
item.mod.visit(node) item.mod.visit(node)
......
...@@ -115,7 +115,7 @@ staticAnalysisView.prototype.run = function () { ...@@ -115,7 +115,7 @@ staticAnalysisView.prototype.run = function () {
length: parseInt(split[1]) length: parseInt(split[1])
} }
location = self.appAPI.offsetToLineColumn(location, file) location = self.appAPI.offsetToLineColumn(location, file)
location = self.lastCompilationResult.sourceList[file] + ':' + (location.start.line + 1) + ':' + (location.start.column + 1) + ': ' location = Object.keys(self.lastCompilationResult.contracts)[file] + ':' + (location.start.line + 1) + ':' + (location.start.column + 1) + ':'
} }
warningCount++ warningCount++
var msg = yo`<span>${location} ${item.warning} ${item.more ? yo`<span><br><a href="${item.more}" target="blank">more</a></span>` : yo`<span></span>`}</span>` var msg = yo`<span>${location} ${item.warning} ${item.more ? yo`<span><br><a href="${item.more}" target="blank">more</a></span>` : yo`<span></span>`}</span>`
......
...@@ -305,9 +305,9 @@ function compileTab (container, appAPI, appEvents, opts) { ...@@ -305,9 +305,9 @@ function compileTab (container, appAPI, appEvents, opts) {
} }
if (!error) { if (!error) {
if (data.contracts) { if (data.contracts) {
for (var contract in data.contracts) { appAPI.visitContracts((contract) => {
appAPI.compilationMessage(contract, $(errorContainer), {type: 'success'}) appAPI.compilationMessage({ formattedMessage: contract.name }, $(errorContainer), {type: 'success'})
} })
} }
} }
}) })
...@@ -315,7 +315,7 @@ function compileTab (container, appAPI, appEvents, opts) { ...@@ -315,7 +315,7 @@ function compileTab (container, appAPI, appEvents, opts) {
appEvents.staticAnalysis.register('staticAnaysisWarning', (count) => { appEvents.staticAnalysis.register('staticAnaysisWarning', (count) => {
if (count) { if (count) {
var errorContainer = container.querySelector('.error') var errorContainer = container.querySelector('.error')
appAPI.compilationMessage(`Static Analysis raised ${count} warning(s) that requires your attention.`, $(errorContainer), { appAPI.compilationMessage({ severity: 'warning', formattedMessage: `Static Analysis raised ${count} warning(s) that requires your attention.` }, $(errorContainer), {
type: 'warning', type: 'warning',
click: () => appAPI.switchTab('staticanalysisView') click: () => appAPI.switchTab('staticanalysisView')
}) })
...@@ -340,14 +340,14 @@ function compileTab (container, appAPI, appEvents, opts) { ...@@ -340,14 +340,14 @@ function compileTab (container, appAPI, appEvents, opts) {
contractNames.innerHTML = '' contractNames.innerHTML = ''
if (success) { if (success) {
contractNames.removeAttribute('disabled') contractNames.removeAttribute('disabled')
for (var name in data.contracts) { appAPI.visitContracts((contract) => {
contractsDetails[name] = parseContracts(name, data.contracts[name], appAPI.currentCompiledSourceCode()) contractsDetails[contract.name] = parseContracts(contract.name, contract.object, appAPI.getSource(contract.file))
var contractName = yo` var contractName = yo`
<option> <option>
${name} ${contract.name}
</option>` </option>`
contractNames.appendChild(contractName) contractNames.appendChild(contractName)
} })
appAPI.resetDapp(contractsDetails) appAPI.resetDapp(contractsDetails)
} else { } else {
contractNames.setAttribute('disabled', true) contractNames.setAttribute('disabled', true)
...@@ -364,11 +364,9 @@ function compileTab (container, appAPI, appEvents, opts) { ...@@ -364,11 +364,9 @@ function compileTab (container, appAPI, appEvents, opts) {
Object.keys(contractProperties).map(propertyName => { Object.keys(contractProperties).map(propertyName => {
var copyDetails = yo`<span class="${css.copyDetails}"><i title="Copy value to clipboard" class="fa fa-clipboard" onclick=${() => { copy(contractProperties[propertyName]) }} aria-hidden="true"></i></span>` var copyDetails = yo`<span class="${css.copyDetails}"><i title="Copy value to clipboard" class="fa fa-clipboard" onclick=${() => { copy(contractProperties[propertyName]) }} aria-hidden="true"></i></span>`
var questionMark = yo`<span class="${css.questionMark}"><i title="${detailsHelpSection()[propertyName]}" class="fa fa-question-circle" aria-hidden="true"></i></span>` var questionMark = yo`<span class="${css.questionMark}"><i title="${detailsHelpSection()[propertyName]}" class="fa fa-question-circle" aria-hidden="true"></i></span>`
var keyDisplayName
(propertyName === 'interface') ? keyDisplayName = 'interface - abi' : keyDisplayName = propertyName
log.appendChild(yo` log.appendChild(yo`
<div class=${css.log}> <div class=${css.log}>
<div class="${css.key}">${keyDisplayName} ${copyDetails} ${questionMark}</div> <div class="${css.key}">${propertyName} ${copyDetails} ${questionMark}</div>
${insertValue(contractProperties, propertyName)} ${insertValue(contractProperties, propertyName)}
</div> </div>
`) `)
...@@ -380,11 +378,9 @@ function compileTab (container, appAPI, appEvents, opts) { ...@@ -380,11 +378,9 @@ function compileTab (container, appAPI, appEvents, opts) {
function insertValue (details, propertyName) { function insertValue (details, propertyName) {
var value = yo`<pre class="${css.value}"></pre>` var value = yo`<pre class="${css.value}"></pre>`
var node var node
if (propertyName === 'bytecode' || propertyName === 'metadataHash' || propertyName === 'swarmLocation' || propertyName === 'Runtime Bytecode' || propertyName === 'Opcodes') { if (propertyName === 'web3Deploy' || propertyName === 'name' || propertyName === 'Assembly') {
node = yo`<div>${details[propertyName].slice(0, 60) + '...'}</div>`
} else if (propertyName === 'web3Deploy' || propertyName === 'name') {
node = yo`<pre>${details[propertyName]}</pre>` node = yo`<pre>${details[propertyName]}</pre>`
} else if (propertyName === 'interface' || propertyName === 'metadata') { } else if (propertyName === 'abi' || propertyName === 'metadata') {
var treeView = new TreeView({ var treeView = new TreeView({
extractData: function (item, parent, key) { extractData: function (item, parent, key) {
var ret = {} var ret = {}
...@@ -407,7 +403,7 @@ function compileTab (container, appAPI, appEvents, opts) { ...@@ -407,7 +403,7 @@ function compileTab (container, appAPI, appEvents, opts) {
}) })
if (details[propertyName] !== '') { if (details[propertyName] !== '') {
try { try {
node = yo`<div>${treeView.render(JSON.parse(details[propertyName]))}</div>` // catch in case the parsing fails. node = yo`<div>${treeView.render(typeof details[propertyName] === 'object' ? details[propertyName] : JSON.parse(details[propertyName]))}</div>` // catch in case the parsing fails.
} catch (e) { } catch (e) {
node = yo`<div>Unable to display "${propertyName}": ${e.message}</div>` node = yo`<div>Unable to display "${propertyName}": ${e.message}</div>`
} }
...@@ -456,7 +452,7 @@ function detailsHelpSection () { ...@@ -456,7 +452,7 @@ function detailsHelpSection () {
'gasEstimates': 'Gas estimation for each function call', 'gasEstimates': 'Gas estimation for each function call',
'metadata': 'Contains all informations related to the compilation', 'metadata': 'Contains all informations related to the compilation',
'metadataHash': 'Hash representing all metadata information', 'metadataHash': 'Hash representing all metadata information',
'interface': 'ABI: describing all the functions (input/output params, scope, ...)', 'abi': 'ABI: describing all the functions (input/output params, scope, ...)',
'name': 'Name of the compiled contract', 'name': 'Name of the compiled contract',
'swarmLocation': 'Swarm url where all metadata information can be found (contract needs to be published first)', 'swarmLocation': 'Swarm url where all metadata information can be found (contract needs to be published first)',
'web3Deploy': 'Copy/paste this code to any JavaScript/Web3 console to deploy this contract' 'web3Deploy': 'Copy/paste this code to any JavaScript/Web3 console to deploy this contract'
......
...@@ -277,9 +277,9 @@ function contractDropdown (appAPI, appEvents, instanceContainer) { ...@@ -277,9 +277,9 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
function setInputParamsPlaceHolder () { function setInputParamsPlaceHolder () {
createButtonInput.value = '' createButtonInput.value = ''
if (appAPI.getContracts() && selectContractNames.selectedIndex >= 0 && selectContractNames.children.length > 0) { if (appAPI.getContract && selectContractNames.selectedIndex >= 0 && selectContractNames.children.length > 0) {
var contract = appAPI.getContracts()[selectContractNames.children[selectContractNames.selectedIndex].innerHTML] var contract = appAPI.getContract(selectContractNames.children[selectContractNames.selectedIndex].innerHTML)
var ctrabi = txHelper.getConstructorInterface(contract.interface) var ctrabi = txHelper.getConstructorInterface(contract.object.abi)
if (ctrabi.inputs.length) { if (ctrabi.inputs.length) {
createButtonInput.setAttribute('placeholder', txHelper.inputParametersDeclarationToString(ctrabi.inputs)) createButtonInput.setAttribute('placeholder', txHelper.inputParametersDeclarationToString(ctrabi.inputs))
createButtonInput.removeAttribute('disabled') createButtonInput.removeAttribute('disabled')
...@@ -295,18 +295,17 @@ function contractDropdown (appAPI, appEvents, instanceContainer) { ...@@ -295,18 +295,17 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
// ADD BUTTONS AT ADDRESS AND CREATE // ADD BUTTONS AT ADDRESS AND CREATE
function createInstance () { function createInstance () {
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
var contracts = appAPI.getContracts()
var contractName = contractNames.children[contractNames.selectedIndex].innerHTML var contractName = contractNames.children[contractNames.selectedIndex].innerHTML
var contract = appAPI.getContracts()[contractName] var contract = appAPI.getContract(contractName)
if (contract.bytecode.length === 0) { if (contract.object.evm.bytecode.object.length === 0) {
modalDialogCustom.alert('This contract does not implement all functions and thus cannot be created.') modalDialogCustom.alert('This contract does not implement all functions and thus cannot be created.')
return return
} }
var constructor = txHelper.getConstructorInterface(contract.interface) var constructor = txHelper.getConstructorInterface(contract.object.abi)
var args = createButtonInput.value var args = createButtonInput.value
txFormat.buildData(contract, contracts, true, constructor, args, appAPI.udapp(), (error, data) => { txFormat.buildData(contract.object, appAPI.getContracts(), true, constructor, args, appAPI.udapp(), (error, data) => {
if (!error) { if (!error) {
appAPI.logMessage(`creation of ${contractName} pending...`) appAPI.logMessage(`creation of ${contractName} pending...`)
txExecution.createContract(data, appAPI.udapp(), (error, txResult) => { txExecution.createContract(data, appAPI.udapp(), (error, txResult) => {
...@@ -321,7 +320,7 @@ function contractDropdown (appAPI, appEvents, instanceContainer) { ...@@ -321,7 +320,7 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
} }
noInstancesText.style.display = 'none' noInstancesText.style.display = 'none'
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress
instanceContainer.appendChild(appAPI.udapp().renderInstance(contract, address, selectContractNames.value)) instanceContainer.appendChild(appAPI.udapp().renderInstance(contract.object, address, selectContractNames.value))
} else { } else {
appAPI.logMessage(`creation of ${contractName} errored: ` + error) appAPI.logMessage(`creation of ${contractName} errored: ` + error)
} }
...@@ -337,9 +336,9 @@ function contractDropdown (appAPI, appEvents, instanceContainer) { ...@@ -337,9 +336,9 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
function loadFromAddress (appAPI) { function loadFromAddress (appAPI) {
noInstancesText.style.display = 'none' noInstancesText.style.display = 'none'
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
var contract = appAPI.getContracts()[contractNames.children[contractNames.selectedIndex].innerHTML] var contract = appAPI.getContract(contractNames.children[contractNames.selectedIndex].innerHTML)
var address = atAddressButtonInput.value var address = atAddressButtonInput.value
instanceContainer.appendChild(appAPI.udapp().renderInstance(contract, address, selectContractNames.value)) instanceContainer.appendChild(appAPI.udapp().renderInstance(contract.object, address, selectContractNames.value))
} }
// GET NAMES OF ALL THE CONTRACTS // GET NAMES OF ALL THE CONTRACTS
...@@ -348,9 +347,9 @@ function contractDropdown (appAPI, appEvents, instanceContainer) { ...@@ -348,9 +347,9 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
contractNames.innerHTML = '' contractNames.innerHTML = ''
if (success) { if (success) {
selectContractNames.removeAttribute('disabled') selectContractNames.removeAttribute('disabled')
for (var name in data.contracts) { appAPI.visitContracts((contract) => {
contractNames.appendChild(yo`<option>${name}</option>`) contractNames.appendChild(yo`<option>${contract.name}</option>`)
} })
} else { } else {
selectContractNames.setAttribute('disabled', true) selectContractNames.setAttribute('disabled', true)
} }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
var $ = require('jquery') var $ = require('jquery')
var yo = require('yo-yo') var yo = require('yo-yo')
var utils = require('../../lib/utils')
// -------------- styling ---------------------- // -------------- styling ----------------------
// var csjs = require('csjs-inject') // var csjs = require('csjs-inject')
...@@ -93,10 +92,8 @@ Renderer.prototype.error = function (message, container, opt) { ...@@ -93,10 +92,8 @@ Renderer.prototype.error = function (message, container, opt) {
message = yo`<span>${message}</span>` message = yo`<span>${message}</span>`
} else if (message.innerText) { } else if (message.innerText) {
text = message.innerText text = message.innerText
} } else if (message.formattedMessage) {
text = message.formattedMessage
if (!opt.type) {
opt.type = utils.errortype(text)
} }
var errLocation = text.match(/^([^:]*):([0-9]*):(([0-9]*):)? /) var errLocation = text.match(/^([^:]*):([0-9]*):(([0-9]*):)? /)
......
...@@ -12,7 +12,8 @@ function offsetToColumnConverter (compilerEvent) { ...@@ -12,7 +12,8 @@ function offsetToColumnConverter (compilerEvent) {
offsetToColumnConverter.prototype.offsetToLineColumn = function (rawLocation, file, compilationResult) { offsetToColumnConverter.prototype.offsetToLineColumn = function (rawLocation, file, compilationResult) {
if (!this.lineBreakPositionsByContent[file]) { if (!this.lineBreakPositionsByContent[file]) {
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(compilationResult.source.sources[compilationResult.data.sourceList[file]]) var filename = Object.keys(compilationResult.data.sources)[file]
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(compilationResult.source.sources[filename].content)
} }
return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file]) return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
} }
......
'use strict' 'use strict'
function errortype (message) {
return message.match(/^(.*:[0-9]*:[0-9]* )?Warning: /) ? 'warning' : 'error'
}
function groupBy (arr, key) { function groupBy (arr, key) {
return arr.reduce((sum, item) => { return arr.reduce((sum, item) => {
const groupByVal = item[key] const groupByVal = item[key]
...@@ -23,7 +19,6 @@ function escapeRegExp (str) { ...@@ -23,7 +19,6 @@ function escapeRegExp (str) {
} }
module.exports = { module.exports = {
errortype: errortype,
groupBy: groupBy, groupBy: groupBy,
concatWithSeperator: concatWithSeperator, concatWithSeperator: concatWithSeperator,
escapeRegExp: escapeRegExp escapeRegExp: escapeRegExp
......
'use strict' 'use strict'
var Module = { // eslint-disable-line var Module = { // eslint-disable-line
cwrap: function () { return arguments[0] === 'version' ? version : compile }, cwrap: function () { return arguments[0] === 'version' ? version : compileStandard },
writeStringToMemory: function () {}, writeStringToMemory: function () {},
setValue: function () {}, setValue: function () {},
Pointer_stringify: function (value) { return value }, Pointer_stringify: function (value) { return value },
...@@ -12,22 +12,16 @@ var Module = { // eslint-disable-line ...@@ -12,22 +12,16 @@ var Module = { // eslint-disable-line
_compileJSONMulti: {}, _compileJSONMulti: {},
_compileJSONCallback: {}, _compileJSONCallback: {},
_compileJSON: {}, _compileJSON: {},
_malloc: function () {} _malloc: function () {},
_compileStandard: compileStandard
} }
function compile (source, optimization, missingInputs) { function compileStandard (source, missingInputs) {
if (typeof source === 'string') { source = source.replace(/(\t)|(\n)|(\\n)|( )/g, '')
source = JSON.parse(source) var data = mockData[source] // eslint-disable-line
}
var key = optimization.toString()
for (var k in source.sources) {
key += k + source.sources[k]
}
key = key.replace(/(\t)|(\n)|( )/g, '')
var data = mockData[key] // eslint-disable-line
if (data === undefined) { if (data === undefined) {
return JSON.stringify({ return JSON.stringify({
errors: ['mock compiler: source not found'] errors: [{ formattedMessage: 'mock compiler: source not found', severity: 'error' }]
}) })
} else { } else {
data.missingInputs.map(function (item, i) { data.missingInputs.map(function (item, i) {
...@@ -36,7 +30,7 @@ function compile (source, optimization, missingInputs) { ...@@ -36,7 +30,7 @@ function compile (source, optimization, missingInputs) {
} }
}) })
} }
return JSON.stringify(data.result) return data.result
} }
function version () { function version () {
......
...@@ -4,9 +4,9 @@ var examples = require('../../src/app/editor/example-contracts') ...@@ -4,9 +4,9 @@ var examples = require('../../src/app/editor/example-contracts')
var init = require('../helpers/init') var init = require('../helpers/init')
var sauce = require('./sauce') var sauce = require('./sauce')
var sources = [ var sources = {
{'browser/Untitled.sol': examples.ballot.content} 'browser/Untitled.sol': { content: examples.ballot.content }
] }
module.exports = { module.exports = {
before: function (browser, done) { before: function (browser, done) {
......
...@@ -131,15 +131,15 @@ function testInputValues (browser, callback) { ...@@ -131,15 +131,15 @@ function testInputValues (browser, callback) {
// @TODO test: bytes8[3][] type as input // @TODO test: bytes8[3][] type as input
var sources = [ var sources = [
{'browser/Untitled.sol': `pragma solidity ^0.4.0; {'browser/Untitled.sol': {content: `pragma solidity ^0.4.0;
contract TestContract { function f() returns (uint) { return 8; } contract TestContract { function f() returns (uint) { return 8; }
function g() returns (uint, string, bool, uint) { function g() returns (uint, string, bool, uint) {
uint payment = 345; uint payment = 345;
bool payed = true; bool payed = true;
string memory comment = "comment_comment_"; string memory comment = "comment_comment_";
uint month = 4; uint month = 4;
return (payment, comment, payed, month); } }`}, return (payment, comment, payed, month); } }`}},
{'browser/returnValues.sol': `pragma solidity ^0.4.0; {'browser/returnValues.sol': {content: `pragma solidity ^0.4.0;
contract testReturnValues { contract testReturnValues {
enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
function retunValues1 () returns (bool _b, uint _u, int _i, address _a) { function retunValues1 () returns (bool _b, uint _u, int _i, address _a) {
...@@ -169,8 +169,8 @@ var sources = [ ...@@ -169,8 +169,8 @@ var sources = [
a[2] = [int(1),10,-5435,45,-7]; a[2] = [int(1),10,-5435,45,-7];
_a1 = a; _a1 = a;
} }
}`}, }`}},
{'browser/inputValues.sol': `pragma solidity ^0.4.0; {'browser/inputValues.sol': {content: `pragma solidity ^0.4.0;
contract test { contract test {
event event1(int _i, uint indexed _u, string indexed _str, bytes4 _b, string _notIndexed); event event1(int _i, uint indexed _u, string indexed _str, bytes4 _b, string _notIndexed);
function inputValue1 (uint _u, int _i, string _str) returns (uint _uret, int _iret, string _strret) { function inputValue1 (uint _u, int _i, string _str) returns (uint _uret, int _iret, string _strret) {
...@@ -183,5 +183,5 @@ var sources = [ ...@@ -183,5 +183,5 @@ var sources = [
_b8ret = _b8; _b8ret = _b8;
event1(-123, 123, "test", 0x1234, "test _ test _ test _ test test _ test test _ test test _ test test _ test test _ test test _ test "); event1(-123, 123, "test", 0x1234, "test _ test _ test _ test test _ test test _ test test _ test test _ test test _ test test _ test ");
} }
}`} }`}}
] ]
...@@ -3,11 +3,9 @@ var contractHelper = require('../helpers/contracts') ...@@ -3,11 +3,9 @@ var contractHelper = require('../helpers/contracts')
var init = require('../helpers/init') var init = require('../helpers/init')
var sauce = require('./sauce') var sauce = require('./sauce')
var sources = [ var sources = {
{ 'localhost/folder1/contract2.sol': { content: 'contract test2 { function get () returns (uint) { return 11; }}' }
'localhost/folder1/contract2.sol': 'contract test2 { function get () returns (uint) { return 11; }}' }
}
]
module.exports = { module.exports = {
before: function (browser, done) { before: function (browser, done) {
...@@ -43,7 +41,7 @@ function runTests (browser, testData) { ...@@ -43,7 +41,7 @@ function runTests (browser, testData) {
.assert.containsText('[data-path="localhost/folder1/contract2.sol"]', 'contract2.sol') .assert.containsText('[data-path="localhost/folder1/contract2.sol"]', 'contract2.sol')
.click('[data-path="localhost/folder1/contract2.sol"]') .click('[data-path="localhost/folder1/contract2.sol"]')
.waitForElementPresent('#compileTabView select option', 50000, true, function () { .waitForElementPresent('#compileTabView select option', 50000, true, function () {
contractHelper.verifyContract(browser, ['localhost/folder1/contract2.sol:test2'], function () { contractHelper.verifyContract(browser, ['test2'], function () {
browser.click('.websocketconn').end() browser.click('.websocketconn').end()
}) })
}) })
......
...@@ -36,8 +36,8 @@ function runTests (browser) { ...@@ -36,8 +36,8 @@ function runTests (browser) {
} }
function testSimpleContract (browser, callback) { function testSimpleContract (browser, callback) {
contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['browser/Untitled.sol:test1', 'browser/Untitled.sol:test2'], function () { contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['test1', 'test2'], function () {
callback(null, browser) browser.end()
}) })
} }
......
...@@ -36,15 +36,14 @@ function runTests (browser) { ...@@ -36,15 +36,14 @@ function runTests (browser) {
browser browser
.waitForElementVisible('.newFile', 10000) .waitForElementVisible('.newFile', 10000)
.click('.compileView') .click('.compileView')
contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['browser/Untitled.sol:TooMuchGas', 'browser/Untitled.sol:test1', 'browser/Untitled.sol:test2'], function () { contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['TooMuchGas', 'test1', 'test2'], function () {
browser browser
.click('.staticanalysisView') .click('.staticanalysisView')
.click('#staticanalysisView button') .click('#staticanalysisView button')
.waitForElementPresent('#staticanalysisresult .warning', 2000, true, function () { .waitForElementPresent('#staticanalysisresult .warning', 2000, true, function () {
dom.listSelectorContains(['browser/Untitled.sol:2:33: Use of tx.origin', dom.listSelectorContains(['browser/Untitled.sol:2:33: Use of tx.origin',
'Fallback function of contract browser/Untitled.sol:TooMuchGas requires too much gas', 'Fallback function of contract TooMuchGas requires too much gas'],
'TooMuchGas.(): Variables have very similar names test and test1.'], '#staticanalysisresult .warning span',
'#staticanalysisresult .warning',
browser, function () { browser, function () {
browser.end() browser.end()
} }
......
...@@ -9,6 +9,8 @@ var compiler = solc(require('../../soljson')) ...@@ -9,6 +9,8 @@ var compiler = solc(require('../../soljson'))
var fs = require('fs') var fs = require('fs')
var path = require('path') var path = require('path')
var compilerInput = require('../../src/app/compiler/compiler-input.js')
var testFiles = [ var testFiles = [
'KingOfTheEtherThrone.sol', 'KingOfTheEtherThrone.sol',
'assembly.sol', 'assembly.sol',
...@@ -31,8 +33,8 @@ var testFiles = [ ...@@ -31,8 +33,8 @@ var testFiles = [
var testFileAsts = {} var testFileAsts = {}
testFiles.forEach((fileName) => { testFiles.forEach((fileName) => {
var contents = fs.readFileSync(path.join(__dirname, 'test-contracts', fileName), 'utf8') var content = fs.readFileSync(path.join(__dirname, 'test-contracts', fileName), 'utf8')
testFileAsts[fileName] = compiler.compile(contents, 0) testFileAsts[fileName] = JSON.parse(compiler.compileStandardWrapper(compilerInput({'test.sol': { content: content }}, { optimize: false })))
}) })
test('Integration test thisLocal.js', function (t) { test('Integration test thisLocal.js', function (t) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment