From 192e0a9dd0f378cfbd5a3c37d09f041b772df90b Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Tue, 30 Jan 2018 15:34:38 -0500 Subject: [PATCH 01/12] add missing dependencies required for compiler wrapper code --- remix-solidity/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/remix-solidity/package.json b/remix-solidity/package.json index 8c105841ee..c17eccc7fc 100644 --- a/remix-solidity/package.json +++ b/remix-solidity/package.json @@ -23,6 +23,9 @@ "fast-async": "^6.1.2", "remix-core": "latest", "remix-lib": "latest", + "js-base64": "^2.1.9", + "swarmgw": "^0.2.0", + "webworkify": "^1.2.1", "solc": "^0.4.13", "standard": "^7.0.1", "tape": "^4.6.0" From 7eb8cc31ea6d8f6c911aa607d00b435bc2c8d54c Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Tue, 30 Jan 2018 15:37:11 -0500 Subject: [PATCH 02/12] export Compiler in remix-solidity --- remix-solidity/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/remix-solidity/index.js b/remix-solidity/index.js index ef3e559e7a..3b3df20f1b 100644 --- a/remix-solidity/index.js +++ b/remix-solidity/index.js @@ -3,11 +3,13 @@ var SolidityProxy = require('./src/decoder/solidityProxy') var localDecoder = require('./src/decoder/localDecoder') var stateDecoder = require('./src/decoder/stateDecoder') var CodeAnalysis = require('./src/analysis/staticAnalysisRunner') +var Compiler = require('./src/compiler/compiler') module.exports = { InternalCallTree: InternalCallTree, SolidityProxy: SolidityProxy, localDecoder: localDecoder, stateDecoder: stateDecoder, - CodeAnalysis: CodeAnalysis + CodeAnalysis: CodeAnalysis, + Compiler: Compiler } From deb1a4f394c09708e35835b4814cc71f3bace0fa Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Tue, 30 Jan 2018 15:37:27 -0500 Subject: [PATCH 03/12] move compiler code from browser-solidity including txHelper --- .../src/compiler/compiler-imports.js | 85 +++++ remix-solidity/src/compiler/compiler-input.js | 21 + .../src/compiler/compiler-worker.js | 45 +++ remix-solidity/src/compiler/compiler.js | 358 ++++++++++++++++++ remix-solidity/src/compiler/txHelper.js | 129 +++++++ 5 files changed, 638 insertions(+) create mode 100644 remix-solidity/src/compiler/compiler-imports.js create mode 100644 remix-solidity/src/compiler/compiler-input.js create mode 100644 remix-solidity/src/compiler/compiler-worker.js create mode 100644 remix-solidity/src/compiler/compiler.js create mode 100644 remix-solidity/src/compiler/txHelper.js diff --git a/remix-solidity/src/compiler/compiler-imports.js b/remix-solidity/src/compiler/compiler-imports.js new file mode 100644 index 0000000000..a6162cb972 --- /dev/null +++ b/remix-solidity/src/compiler/compiler-imports.js @@ -0,0 +1,85 @@ +'use strict' +// TODO: can just use request or fetch instead +var $ = require('jquery') +var base64 = require('js-base64').Base64 +var swarmgw = require('swarmgw') + +module.exports = { + handleGithubCall: function (root, path, cb) { + return $.getJSON('https://api.github.com/repos/' + root + '/contents/' + path) + .done(function (data) { + if ('content' in data) { + cb(null, base64.decode(data.content), root + '/' + path) + } else { + cb('Content not received') + } + }) + .fail(function (xhr, text, err) { + // NOTE: on some browsers, err equals to '' for certain errors (such as offline browser) + cb(err || 'Unknown transport error') + }) + }, + + handleSwarmImport: function (url, cb) { + swarmgw.get(url, function (err, content) { + cb(err, content, url) + }) + }, + + handleIPFS: function (url, cb) { + // replace ipfs:// with /ipfs/ + url = url.replace(/^ipfs:\/\/?/, 'ipfs/') + + return $.ajax({ type: 'GET', url: 'https://gateway.ipfs.io/' + url }) + .done(function (data) { + cb(null, data, url) + }) + .fail(function (xhr, text, err) { + // NOTE: on some browsers, err equals to '' for certain errors (such as offline browser) + cb(err || 'Unknown transport error') + }) + }, + + handlers: function () { + return [ + { type: 'github', match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)\/(.*)/, handler: (match, cb) => { this.handleGithubCall(match[3], match[4], cb) } }, + { type: 'swarm', match: /^(bzz[ri]?:\/\/?.*)$/, handler: (match, cb) => { this.handleSwarmImport(match[1], cb) } }, + { type: 'ipfs', match: /^(ipfs:\/\/?.+)/, handler: (match, cb) => { this.handleIPFS(match[1], cb) } } + ] + }, + + import: function (url, cb) { + var handlers = this.handlers() + + var found = false + handlers.forEach(function (handler) { + if (found) { + return + } + + var match = handler.match.exec(url) + if (match) { + found = true + + // TODO: this needs to be moved to the caller + $('#output').append($('
').append($('
').text('Loading ' + url + ' ...')))
+        handler.handler(match, function (err, content, cleanUrl) {
+          if (err) {
+            cb('Unable to import "' + cleanUrl + '": ' + err)
+            return
+          }
+
+          cb(null, content, cleanUrl, handler.type, url)
+        })
+      }
+    })
+
+    if (found) {
+      return
+    } else if (/^[^:]*:\/\//.exec(url)) {
+      cb('Unable to import "' + url + '": Unsupported URL schema')
+    } else {
+      cb('Unable to import "' + url + '": File not found')
+    }
+  }
+}
diff --git a/remix-solidity/src/compiler/compiler-input.js b/remix-solidity/src/compiler/compiler-input.js
new file mode 100644
index 0000000000..0929a3be3d
--- /dev/null
+++ b/remix-solidity/src/compiler/compiler-input.js
@@ -0,0 +1,21 @@
+'use strict'
+
+module.exports = (sources, opts) => {
+  return JSON.stringify({
+    language: 'Solidity',
+    sources: sources,
+    settings: {
+      optimizer: {
+        enabled: opts.optimize === true || opts.optimize === 1,
+        runs: 200
+      },
+      libraries: opts.libraries,
+      outputSelection: {
+        '*': {
+          '': [ 'legacyAST' ],
+          '*': [ 'abi', 'metadata', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
+        }
+      }
+    }
+  })
+}
diff --git a/remix-solidity/src/compiler/compiler-worker.js b/remix-solidity/src/compiler/compiler-worker.js
new file mode 100644
index 0000000000..14e630aeaf
--- /dev/null
+++ b/remix-solidity/src/compiler/compiler-worker.js
@@ -0,0 +1,45 @@
+'use strict'
+
+var solc = require('solc/wrapper')
+
+var compileJSON = function () { return '' }
+var missingInputs = []
+
+module.exports = function (self) {
+  self.addEventListener('message', function (e) {
+    var data = e.data
+    switch (data.cmd) {
+      case 'loadVersion':
+        delete self.Module
+        // NOTE: workaround some browsers?
+        self.Module = undefined
+
+        compileJSON = null
+
+        self.importScripts(data.data)
+
+        var compiler = solc(self.Module)
+
+        compileJSON = function (input) {
+          try {
+            return compiler.compileStandardWrapper(input, function (path) {
+              missingInputs.push(path)
+              return { 'error': 'Deferred import' }
+            })
+          } catch (exception) {
+            return JSON.stringify({ error: 'Uncaught JavaScript exception:\n' + exception })
+          }
+        }
+
+        self.postMessage({
+          cmd: 'versionLoaded',
+          data: compiler.version()
+        })
+        break
+      case 'compile':
+        missingInputs.length = 0
+        self.postMessage({cmd: 'compiled', job: data.job, data: compileJSON(data.input), missingInputs: missingInputs})
+        break
+    }
+  }, false)
+}
diff --git a/remix-solidity/src/compiler/compiler.js b/remix-solidity/src/compiler/compiler.js
new file mode 100644
index 0000000000..d5b59cc567
--- /dev/null
+++ b/remix-solidity/src/compiler/compiler.js
@@ -0,0 +1,358 @@
+'use strict'
+
+var solc = require('solc/wrapper')
+var solcABI = require('solc/abi')
+
+var webworkify = require('webworkify')
+
+var compilerInput = require('./compiler-input')
+
+var remixLib = require('remix-lib')
+var EventManager = remixLib.EventManager
+
+var txHelper = require('./txHelper')
+
+/*
+  trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration
+*/
+function Compiler (handleImportCall) {
+  var self = this
+  this.event = new EventManager()
+
+  var compileJSON
+
+  var worker = null
+
+  var currentVersion
+
+  var optimize = false
+
+  this.setOptimize = function (_optimize) {
+    optimize = _optimize
+  }
+
+  var compilationStartTime = null
+  this.event.register('compilationFinished', (success, data, source) => {
+    if (success && compilationStartTime) {
+      this.event.trigger('compilationDuration', [(new Date().getTime()) - compilationStartTime])
+    }
+    compilationStartTime = null
+  })
+
+  this.event.register('compilationStarted', () => {
+    compilationStartTime = new Date().getTime()
+  })
+
+  var internalCompile = function (files, target, missingInputs) {
+    gatherImports(files, target, missingInputs, function (error, input) {
+      if (error) {
+        self.lastCompilationResult = null
+        self.event.trigger('compilationFinished', [false, {'error': { formattedMessage: error, severity: 'error' }}, files])
+      } else {
+        compileJSON(input, optimize ? 1 : 0)
+      }
+    })
+  }
+
+  var compile = function (files, target) {
+    self.event.trigger('compilationStarted', [])
+    internalCompile(files, target)
+  }
+  this.compile = compile
+
+  function setCompileJSON (_compileJSON) {
+    compileJSON = _compileJSON
+  }
+  this.setCompileJSON = setCompileJSON // this is exposed for testing
+
+  function onCompilerLoaded (version) {
+    currentVersion = version
+    self.event.trigger('compilerLoaded', [version])
+  }
+
+  function onInternalCompilerLoaded () {
+    if (worker === null) {
+      var compiler = solc(window.Module)
+
+      compileJSON = function (source, optimize, cb) {
+        var missingInputs = []
+        var missingInputsCallback = function (path) {
+          missingInputs.push(path)
+          return { error: 'Deferred import' }
+        }
+
+        var result
+        try {
+          var input = compilerInput(source.sources, {optimize: optimize, target: source.target})
+          result = compiler.compileStandardWrapper(input, missingInputsCallback)
+          result = JSON.parse(result)
+        } catch (exception) {
+          result = { error: 'Uncaught JavaScript exception:\n' + exception }
+        }
+
+        compilationFinished(result, missingInputs, source)
+      }
+      onCompilerLoaded(compiler.version())
+    }
+  }
+
+  this.lastCompilationResult = {
+    data: 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) {
+    var noFatalErrors = true // ie warnings are ok
+
+    function isValidError (error) {
+      // The deferred import is not a real error
+      // FIXME: maybe have a better check?
+      if (/Deferred import/.exec(error.message)) {
+        return false
+      }
+
+      return error.severity !== 'warning'
+    }
+
+    if (data['error'] !== undefined) {
+      // Ignore warnings (and the 'Deferred import' error as those are generated by us as a workaround
+      if (isValidError(data['error'])) {
+        noFatalErrors = false
+      }
+    }
+    if (data['errors'] !== undefined) {
+      data['errors'].forEach(function (err) {
+        // Ignore warnings and the 'Deferred import' error as those are generated by us as a workaround
+        if (isValidError(err)) {
+          noFatalErrors = false
+        }
+      })
+    }
+
+    if (!noFatalErrors) {
+      // There are fatal errors - abort here
+      self.lastCompilationResult = null
+      self.event.trigger('compilationFinished', [false, data, source])
+    } else if (missingInputs !== undefined && missingInputs.length > 0) {
+      // try compiling again with the new set of inputs
+      internalCompile(source.sources, source.target, missingInputs)
+    } else {
+      data = updateInterface(data)
+
+      self.lastCompilationResult = {
+        data: data,
+        source: source
+      }
+      self.event.trigger('compilationFinished', [true, data, source])
+    }
+  }
+
+  this.loadVersion = function (usingWorker, url) {
+    console.log('Loading ' + url + ' ' + (usingWorker ? 'with worker' : 'without worker'))
+    self.event.trigger('loadingCompiler', [url, usingWorker])
+
+    if (usingWorker) {
+      loadWorker(url)
+    } else {
+      loadInternal(url)
+    }
+  }
+
+  function loadInternal (url) {
+    delete window.Module
+    // NOTE: workaround some browsers?
+    window.Module = undefined
+
+    // Set a safe fallback until the new one is loaded
+    setCompileJSON(function (source, optimize) {
+      compilationFinished({ error: { formattedMessage: 'Compiler not yet loaded.' } })
+    })
+
+    var newScript = document.createElement('script')
+    newScript.type = 'text/javascript'
+    newScript.src = url
+    document.getElementsByTagName('head')[0].appendChild(newScript)
+    var check = window.setInterval(function () {
+      if (!window.Module) {
+        return
+      }
+      window.clearInterval(check)
+      onInternalCompilerLoaded()
+    }, 200)
+  }
+
+  function loadWorker (url) {
+    if (worker !== null) {
+      worker.terminate()
+    }
+    worker = webworkify(require('./compiler-worker.js'))
+    var jobs = []
+    worker.addEventListener('message', function (msg) {
+      var data = msg.data
+      switch (data.cmd) {
+        case 'versionLoaded':
+          onCompilerLoaded(data.data)
+          break
+        case 'compiled':
+          var result
+          try {
+            result = JSON.parse(data.data)
+          } catch (exception) {
+            result = { 'error': 'Invalid JSON output from the compiler: ' + exception }
+          }
+          var sources = {}
+          if (data.job in jobs !== undefined) {
+            sources = jobs[data.job].sources
+            delete jobs[data.job]
+          }
+          compilationFinished(result, data.missingInputs, sources)
+          break
+      }
+    })
+    worker.onerror = function (msg) {
+      compilationFinished({ error: 'Worker error: ' + msg.data })
+    }
+    worker.addEventListener('error', function (msg) {
+      compilationFinished({ error: 'Worker error: ' + msg.data })
+    })
+    compileJSON = function (source, optimize) {
+      jobs.push({sources: source})
+      worker.postMessage({cmd: 'compile', job: jobs.length - 1, input: compilerInput(source.sources, {optimize: optimize, target: source.target})})
+    }
+    worker.postMessage({cmd: 'loadVersion', data: url})
+  }
+
+  function gatherImports (files, target, importHints, cb) {
+    importHints = importHints || []
+
+    // FIXME: This will only match imports if the file begins with one.
+    //        It should tokenize by lines and check each.
+    // eslint-disable-next-line no-useless-escape
+    var importRegex = /^\s*import\s*[\'\"]([^\'\"]+)[\'\"];/g
+
+    for (var fileName in files) {
+      var match
+      while ((match = importRegex.exec(files[fileName].content))) {
+        var importFilePath = match[1]
+        if (importFilePath.startsWith('./')) {
+          var path = /(.*\/).*/.exec(target)
+          if (path !== null) {
+            importFilePath = importFilePath.replace('./', path[1])
+          } else {
+            importFilePath = importFilePath.slice(2)
+          }
+        }
+
+        // FIXME: should be using includes or sets, but there's also browser compatibility..
+        if (importHints.indexOf(importFilePath) === -1) {
+          importHints.push(importFilePath)
+        }
+      }
+    }
+
+    while (importHints.length > 0) {
+      var m = importHints.pop()
+      if (m in files) {
+        continue
+      }
+
+      handleImportCall(m, function (err, content) {
+        if (err) {
+          cb(err)
+        } else {
+          files[m] = { content }
+          gatherImports(files, target, importHints, cb)
+        }
+      })
+
+      return
+    }
+
+    cb(null, { 'sources': files, 'target': target })
+  }
+
+  function truncateVersion (version) {
+    var tmp = /^(\d+.\d+.\d+)/.exec(version)
+    if (tmp) {
+      return tmp[1]
+    }
+    return version
+  }
+
+  function updateInterface (data) {
+    txHelper.visitContracts(data.contracts, (contract) => {
+      data.contracts[contract.file][contract.name].abi = solcABI.update(truncateVersion(currentVersion), contract.object.abi)
+    })
+    return data
+  }
+}
+
+module.exports = Compiler
diff --git a/remix-solidity/src/compiler/txHelper.js b/remix-solidity/src/compiler/txHelper.js
new file mode 100644
index 0000000000..81275a835c
--- /dev/null
+++ b/remix-solidity/src/compiler/txHelper.js
@@ -0,0 +1,129 @@
+'use strict'
+var ethJSABI = require('ethereumjs-abi')
+var $ = require('jquery')
+
+module.exports = {
+  encodeParams: function (funABI, args) {
+    var types = []
+    if (funABI.inputs && funABI.inputs.length) {
+      for (var i = 0; i < funABI.inputs.length; i++) {
+        var type = funABI.inputs[i].type
+        types.push(type)
+        if (args.length < types.length) {
+          args.push('')
+        }
+      }
+    }
+
+    // NOTE: the caller will concatenate the bytecode and this
+    //       it could be done here too for consistency
+    return ethJSABI.rawEncode(types, args)
+  },
+
+  encodeFunctionId: function (funABI) {
+    var types = []
+    if (funABI.inputs && funABI.inputs.length) {
+      for (var i = 0; i < funABI.inputs.length; i++) {
+        types.push(funABI.inputs[i].type)
+      }
+    }
+
+    return ethJSABI.methodID(funABI.name, types)
+  },
+
+  sortAbiFunction: function (contractabi) {
+    var abi = contractabi.sort(function (a, b) {
+      if (a.name > b.name) {
+        return -1
+      } else {
+        return 1
+      }
+    }).sort(function (a, b) {
+      if (a.constant === true) {
+        return -1
+      } else {
+        return 1
+      }
+    })
+    return abi
+  },
+
+  getConstructorInterface: function (abi) {
+    var funABI = { 'name': '', 'inputs': [], 'type': 'constructor', 'outputs': [] }
+    if (typeof abi === 'string') {
+      try {
+        abi = JSON.parse(abi)
+      } catch (e) {
+        console.log('exception retrieving ctor abi ' + abi)
+        return funABI
+      }
+    }
+
+    for (var i = 0; i < abi.length; i++) {
+      if (abi[i].type === 'constructor') {
+        funABI.inputs = abi[i].inputs || []
+        break
+      }
+    }
+
+    return funABI
+  },
+
+  getFunction: function (abi, fnName) {
+    for (var i = 0; i < abi.length; i++) {
+      if (abi[i].name === fnName) {
+        return abi[i]
+      }
+    }
+    return null
+  },
+
+  getFallbackInterface: function (abi) {
+    for (var i = 0; i < abi.length; i++) {
+      if (abi[i].type === 'fallback') {
+        return abi[i]
+      }
+    }
+  },
+
+  /**
+    * 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
+    */
+  getContract: (contractName, contracts) => {
+    for (var file in contracts) {
+      if (contracts[file][contractName]) {
+        return { object: contracts[file][contractName], file: file }
+      }
+    }
+    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) {
+    var inputs = ''
+    if (abiinputs) {
+      $.each(abiinputs, function (i, inp) {
+        if (inputs !== '') {
+          inputs += ', '
+        }
+        inputs += inp.type + ' ' + inp.name
+      })
+    }
+    return inputs
+  }
+}

From 6514fe867d200141cb845917de5c907ca7616d6d Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Tue, 30 Jan 2018 15:42:06 -0500
Subject: [PATCH 04/12] remove unused methods

---
 remix-solidity/src/compiler/txHelper.js | 98 +------------------------
 1 file changed, 1 insertion(+), 97 deletions(-)

diff --git a/remix-solidity/src/compiler/txHelper.js b/remix-solidity/src/compiler/txHelper.js
index 81275a835c..b9337cf36c 100644
--- a/remix-solidity/src/compiler/txHelper.js
+++ b/remix-solidity/src/compiler/txHelper.js
@@ -1,90 +1,6 @@
 'use strict'
-var ethJSABI = require('ethereumjs-abi')
-var $ = require('jquery')
 
 module.exports = {
-  encodeParams: function (funABI, args) {
-    var types = []
-    if (funABI.inputs && funABI.inputs.length) {
-      for (var i = 0; i < funABI.inputs.length; i++) {
-        var type = funABI.inputs[i].type
-        types.push(type)
-        if (args.length < types.length) {
-          args.push('')
-        }
-      }
-    }
-
-    // NOTE: the caller will concatenate the bytecode and this
-    //       it could be done here too for consistency
-    return ethJSABI.rawEncode(types, args)
-  },
-
-  encodeFunctionId: function (funABI) {
-    var types = []
-    if (funABI.inputs && funABI.inputs.length) {
-      for (var i = 0; i < funABI.inputs.length; i++) {
-        types.push(funABI.inputs[i].type)
-      }
-    }
-
-    return ethJSABI.methodID(funABI.name, types)
-  },
-
-  sortAbiFunction: function (contractabi) {
-    var abi = contractabi.sort(function (a, b) {
-      if (a.name > b.name) {
-        return -1
-      } else {
-        return 1
-      }
-    }).sort(function (a, b) {
-      if (a.constant === true) {
-        return -1
-      } else {
-        return 1
-      }
-    })
-    return abi
-  },
-
-  getConstructorInterface: function (abi) {
-    var funABI = { 'name': '', 'inputs': [], 'type': 'constructor', 'outputs': [] }
-    if (typeof abi === 'string') {
-      try {
-        abi = JSON.parse(abi)
-      } catch (e) {
-        console.log('exception retrieving ctor abi ' + abi)
-        return funABI
-      }
-    }
-
-    for (var i = 0; i < abi.length; i++) {
-      if (abi[i].type === 'constructor') {
-        funABI.inputs = abi[i].inputs || []
-        break
-      }
-    }
-
-    return funABI
-  },
-
-  getFunction: function (abi, fnName) {
-    for (var i = 0; i < abi.length; i++) {
-      if (abi[i].name === fnName) {
-        return abi[i]
-      }
-    }
-    return null
-  },
-
-  getFallbackInterface: function (abi) {
-    for (var i = 0; i < abi.length; i++) {
-      if (abi[i].type === 'fallback') {
-        return abi[i]
-      }
-    }
-  },
 
   /**
     * return the contract obj of the given @arg name. Uses last compilation result.
@@ -112,18 +28,6 @@ module.exports = {
         if (cb({ name: name, object: contracts[file][name], file: file })) return
       }
     }
-  },
-
-  inputParametersDeclarationToString: function (abiinputs) {
-    var inputs = ''
-    if (abiinputs) {
-      $.each(abiinputs, function (i, inp) {
-        if (inputs !== '') {
-          inputs += ', '
-        }
-        inputs += inp.type + ' ' + inp.name
-      })
-    }
-    return inputs
   }
+
 }

From 0713a146ed38965febecbe38d42fd944da6210bf Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Tue, 30 Jan 2018 15:50:37 -0500
Subject: [PATCH 05/12] remove compiler-imports back to browser-solidity (still
 too specific to browser-solidity)

---
 remix-solidity/package.json                   |  2 -
 .../src/compiler/compiler-imports.js          | 85 -------------------
 2 files changed, 87 deletions(-)
 delete mode 100644 remix-solidity/src/compiler/compiler-imports.js

diff --git a/remix-solidity/package.json b/remix-solidity/package.json
index c17eccc7fc..a5d55cc919 100644
--- a/remix-solidity/package.json
+++ b/remix-solidity/package.json
@@ -23,8 +23,6 @@
     "fast-async": "^6.1.2",
     "remix-core": "latest",
     "remix-lib": "latest",
-    "js-base64": "^2.1.9",
-    "swarmgw": "^0.2.0",
     "webworkify": "^1.2.1",
     "solc": "^0.4.13",
     "standard": "^7.0.1",
diff --git a/remix-solidity/src/compiler/compiler-imports.js b/remix-solidity/src/compiler/compiler-imports.js
deleted file mode 100644
index a6162cb972..0000000000
--- a/remix-solidity/src/compiler/compiler-imports.js
+++ /dev/null
@@ -1,85 +0,0 @@
-'use strict'
-// TODO: can just use request or fetch instead
-var $ = require('jquery')
-var base64 = require('js-base64').Base64
-var swarmgw = require('swarmgw')
-
-module.exports = {
-  handleGithubCall: function (root, path, cb) {
-    return $.getJSON('https://api.github.com/repos/' + root + '/contents/' + path)
-      .done(function (data) {
-        if ('content' in data) {
-          cb(null, base64.decode(data.content), root + '/' + path)
-        } else {
-          cb('Content not received')
-        }
-      })
-      .fail(function (xhr, text, err) {
-        // NOTE: on some browsers, err equals to '' for certain errors (such as offline browser)
-        cb(err || 'Unknown transport error')
-      })
-  },
-
-  handleSwarmImport: function (url, cb) {
-    swarmgw.get(url, function (err, content) {
-      cb(err, content, url)
-    })
-  },
-
-  handleIPFS: function (url, cb) {
-    // replace ipfs:// with /ipfs/
-    url = url.replace(/^ipfs:\/\/?/, 'ipfs/')
-
-    return $.ajax({ type: 'GET', url: 'https://gateway.ipfs.io/' + url })
-      .done(function (data) {
-        cb(null, data, url)
-      })
-      .fail(function (xhr, text, err) {
-        // NOTE: on some browsers, err equals to '' for certain errors (such as offline browser)
-        cb(err || 'Unknown transport error')
-      })
-  },
-
-  handlers: function () {
-    return [
-      { type: 'github', match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)\/(.*)/, handler: (match, cb) => { this.handleGithubCall(match[3], match[4], cb) } },
-      { type: 'swarm', match: /^(bzz[ri]?:\/\/?.*)$/, handler: (match, cb) => { this.handleSwarmImport(match[1], cb) } },
-      { type: 'ipfs', match: /^(ipfs:\/\/?.+)/, handler: (match, cb) => { this.handleIPFS(match[1], cb) } }
-    ]
-  },
-
-  import: function (url, cb) {
-    var handlers = this.handlers()
-
-    var found = false
-    handlers.forEach(function (handler) {
-      if (found) {
-        return
-      }
-
-      var match = handler.match.exec(url)
-      if (match) {
-        found = true
-
-        // TODO: this needs to be moved to the caller
-        $('#output').append($('
').append($('
').text('Loading ' + url + ' ...')))
-        handler.handler(match, function (err, content, cleanUrl) {
-          if (err) {
-            cb('Unable to import "' + cleanUrl + '": ' + err)
-            return
-          }
-
-          cb(null, content, cleanUrl, handler.type, url)
-        })
-      }
-    })
-
-    if (found) {
-      return
-    } else if (/^[^:]*:\/\//.exec(url)) {
-      cb('Unable to import "' + url + '": Unsupported URL schema')
-    } else {
-      cb('Unable to import "' + url + '": File not found')
-    }
-  }
-}

From c54ce861af1ed9fcb79f484cb6753bcb254a5830 Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Tue, 30 Jan 2018 15:55:05 -0500
Subject: [PATCH 06/12] export CompilerInput until browser-solidity/ci can be
 refactored

---
 remix-solidity/index.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/remix-solidity/index.js b/remix-solidity/index.js
index 3b3df20f1b..e7fc83949d 100644
--- a/remix-solidity/index.js
+++ b/remix-solidity/index.js
@@ -4,6 +4,7 @@ var localDecoder = require('./src/decoder/localDecoder')
 var stateDecoder = require('./src/decoder/stateDecoder')
 var CodeAnalysis = require('./src/analysis/staticAnalysisRunner')
 var Compiler = require('./src/compiler/compiler')
+var CompilerInput = require('./src/compiler/compiler-input')
 
 module.exports = {
   InternalCallTree: InternalCallTree,
@@ -11,5 +12,6 @@ module.exports = {
   localDecoder: localDecoder,
   stateDecoder: stateDecoder,
   CodeAnalysis: CodeAnalysis,
-  Compiler: Compiler
+  Compiler: Compiler,
+  CompilerInput: CompilerInput
 }

From 2e2d9df377d0abe15baef372bf54e076fc97c7fc Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Tue, 30 Jan 2018 16:25:32 -0500
Subject: [PATCH 07/12] make handleImportCall optional

---
 remix-solidity/src/compiler/compiler.js | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/remix-solidity/src/compiler/compiler.js b/remix-solidity/src/compiler/compiler.js
index d5b59cc567..98c4eedafc 100644
--- a/remix-solidity/src/compiler/compiler.js
+++ b/remix-solidity/src/compiler/compiler.js
@@ -324,14 +324,16 @@ function Compiler (handleImportCall) {
         continue
       }
 
-      handleImportCall(m, function (err, content) {
-        if (err) {
-          cb(err)
-        } else {
-          files[m] = { content }
-          gatherImports(files, target, importHints, cb)
-        }
-      })
+      if (handleImportCall) {
+        handleImportCall(m, function (err, content) {
+          if (err) {
+            cb(err)
+          } else {
+            files[m] = { content }
+            gatherImports(files, target, importHints, cb)
+          }
+        })
+      }
 
       return
     }

From 748aef29a8fd58a5803a8af1f3ddcf8bd5e66b9d Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Wed, 31 Jan 2018 14:07:52 -0500
Subject: [PATCH 08/12] make compiler more node friendly

---
 remix-solidity/package.json             | 6 ++++--
 remix-solidity/src/compiler/compiler.js | 9 ++++++++-
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/remix-solidity/package.json b/remix-solidity/package.json
index a5d55cc919..a084406a06 100644
--- a/remix-solidity/package.json
+++ b/remix-solidity/package.json
@@ -24,13 +24,15 @@
     "remix-core": "latest",
     "remix-lib": "latest",
     "webworkify": "^1.2.1",
-    "solc": "^0.4.13",
+    "solc": "https://github.com/ethereum/solc-js",
+    "npm-run-all": "^4.0.2",
     "standard": "^7.0.1",
     "tape": "^4.6.0"
   },
   "scripts": {
     "test": "standard && npm run downloadsolc && tape ./test/tests.js",
-    "downloadsolc": "test -e soljson.js || wget https://ethereum.github.io/solc-bin/soljson.js"
+    "downloadsolc": "cd node_modules/solc && (test -e soljson.js || wget https://ethereum.github.io/solc-bin/soljson.js) && cd ..",
+    "prepublish": "mkdirp build; npm-run-all -ls downloadsolc"
   },
   "standard": {
     "ignore": [
diff --git a/remix-solidity/src/compiler/compiler.js b/remix-solidity/src/compiler/compiler.js
index 98c4eedafc..003811b844 100644
--- a/remix-solidity/src/compiler/compiler.js
+++ b/remix-solidity/src/compiler/compiler.js
@@ -72,7 +72,12 @@ function Compiler (handleImportCall) {
 
   function onInternalCompilerLoaded () {
     if (worker === null) {
-      var compiler = solc(window.Module)
+      var compiler;
+      if (typeof(window) == 'undefined') {
+        compiler = require('solc');
+      } else {
+        compiler = solc(window.Module)
+      }
 
       compileJSON = function (source, optimize, cb) {
         var missingInputs = []
@@ -95,6 +100,7 @@ function Compiler (handleImportCall) {
       onCompilerLoaded(compiler.version())
     }
   }
+  this.onInternalCompilerLoaded = onInternalCompilerLoaded; // exposed for use in node
 
   this.lastCompilationResult = {
     data: null,
@@ -215,6 +221,7 @@ function Compiler (handleImportCall) {
     }
   }
 
+  // TODO: needs to be changed to be more node friendly
   this.loadVersion = function (usingWorker, url) {
     console.log('Loading ' + url + ' ' + (usingWorker ? 'with worker' : 'without worker'))
     self.event.trigger('loadingCompiler', [url, usingWorker])

From f9d77a40f9716896a7ff21b28ceb20d6161938f6 Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Wed, 31 Jan 2018 14:38:36 -0500
Subject: [PATCH 09/12] (re)add metadata and userdocs to bring compiler input
 inline with latest changes in browser-solidity

---
 remix-solidity/src/compiler/compiler-input.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/remix-solidity/src/compiler/compiler-input.js b/remix-solidity/src/compiler/compiler-input.js
index 0929a3be3d..2e30630c1d 100644
--- a/remix-solidity/src/compiler/compiler-input.js
+++ b/remix-solidity/src/compiler/compiler-input.js
@@ -13,7 +13,7 @@ module.exports = (sources, opts) => {
       outputSelection: {
         '*': {
           '': [ 'legacyAST' ],
-          '*': [ 'abi', 'metadata', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
+          '*': [ 'abi', 'metadata', 'devdoc', 'userdoc', 'metadata', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
         }
       }
     }

From b4eb542836582ce3ee6c9ac6ed73b2079c13b553 Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Wed, 31 Jan 2018 14:40:27 -0500
Subject: [PATCH 10/12] remove duplicated entry in list

---
 remix-solidity/src/compiler/compiler-input.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/remix-solidity/src/compiler/compiler-input.js b/remix-solidity/src/compiler/compiler-input.js
index 2e30630c1d..c5de89f735 100644
--- a/remix-solidity/src/compiler/compiler-input.js
+++ b/remix-solidity/src/compiler/compiler-input.js
@@ -13,7 +13,7 @@ module.exports = (sources, opts) => {
       outputSelection: {
         '*': {
           '': [ 'legacyAST' ],
-          '*': [ 'abi', 'metadata', 'devdoc', 'userdoc', 'metadata', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
+          '*': [ 'abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
         }
       }
     }

From e2e3e0515452d5b69a67bd266e2ca544f6b95e6f Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Wed, 31 Jan 2018 14:57:39 -0500
Subject: [PATCH 11/12] lint is king

---
 remix-solidity/src/compiler/compiler.js | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/remix-solidity/src/compiler/compiler.js b/remix-solidity/src/compiler/compiler.js
index 003811b844..4238cb6a0f 100644
--- a/remix-solidity/src/compiler/compiler.js
+++ b/remix-solidity/src/compiler/compiler.js
@@ -72,9 +72,9 @@ function Compiler (handleImportCall) {
 
   function onInternalCompilerLoaded () {
     if (worker === null) {
-      var compiler;
-      if (typeof(window) == 'undefined') {
-        compiler = require('solc');
+      var compiler
+      if (typeof (window) === 'undefined') {
+        compiler = require('solc')
       } else {
         compiler = solc(window.Module)
       }
@@ -100,7 +100,8 @@ function Compiler (handleImportCall) {
       onCompilerLoaded(compiler.version())
     }
   }
-  this.onInternalCompilerLoaded = onInternalCompilerLoaded; // exposed for use in node
+  // exposed for use in node
+  this.onInternalCompilerLoaded = onInternalCompilerLoaded
 
   this.lastCompilationResult = {
     data: null,

From a4bb8eab9ae751bd24e332bd5555271160e4d1de Mon Sep 17 00:00:00 2001
From: Iuri Matias 
Date: Wed, 31 Jan 2018 19:06:28 -0500
Subject: [PATCH 12/12] update tests to use solc directly

---
 remix-solidity/test/analysis/staticAnalysisIntegration-test.js | 3 +--
 remix-solidity/test/analysis/staticAnalysisIssues-test.js      | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/remix-solidity/test/analysis/staticAnalysisIntegration-test.js b/remix-solidity/test/analysis/staticAnalysisIntegration-test.js
index 3104a520e4..6afca8cfdd 100644
--- a/remix-solidity/test/analysis/staticAnalysisIntegration-test.js
+++ b/remix-solidity/test/analysis/staticAnalysisIntegration-test.js
@@ -4,8 +4,7 @@ var remixLib = require('remix-lib')
 var StatRunner = require('../../src/analysis/staticAnalysisRunner')
 var compilerInput = remixLib.helpers.compiler.compilerInput
 
-var solc = require('solc/wrapper')
-var compiler = solc(require('../../soljson'))
+var compiler = require('solc')
 
 var fs = require('fs')
 var path = require('path')
diff --git a/remix-solidity/test/analysis/staticAnalysisIssues-test.js b/remix-solidity/test/analysis/staticAnalysisIssues-test.js
index c79618d8b8..63c785b5f7 100644
--- a/remix-solidity/test/analysis/staticAnalysisIssues-test.js
+++ b/remix-solidity/test/analysis/staticAnalysisIssues-test.js
@@ -4,8 +4,7 @@ var remixLib = require('remix-lib')
 var StatRunner = require('../../src/analysis/staticAnalysisRunner')
 var compilerInput = remixLib.helpers.compiler.compilerInput
 
-var solc = require('solc/wrapper')
-var compiler = solc(require('../../soljson'))
+var compiler = require('solc')
 
 var fs = require('fs')
 var path = require('path')