Merge branch 'master' into master

pull/1/head
Sergii Bomko 6 years ago committed by GitHub
commit 3f6010f825
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      package.json
  2. 2
      src/app/components/local-plugin.js
  3. 9
      src/app/components/side-panel.js
  4. 19
      src/app/contract/publishOnSwarm.js
  5. 13
      src/app/debugger/debuggerUI/TxBrowser.js
  6. 12
      src/app/debugger/debuggerUI/vmDebugger/CodeListView.js
  7. 4
      src/app/editor/editor.js
  8. 6
      src/app/files/basicReadOnlyExplorer.js
  9. 3
      src/app/files/file-explorer.js
  10. 17
      src/app/files/fileManager.js
  11. 2
      src/app/files/remixd-handle.js
  12. 8
      src/app/files/styles/file-explorer-styles.js
  13. 3
      src/app/panels/styles/terminal-styles.js
  14. 6
      src/app/panels/terminal.js
  15. 25
      src/app/tabs/compile-tab.js
  16. 4
      src/app/tabs/runTab/model/settings.js
  17. 7
      src/app/tabs/runTab/settings.js
  18. 42
      src/app/ui/auto-complete-popup.js
  19. 3
      src/app/ui/styles/auto-complete-popup-styles.js
  20. 1
      src/app/ui/styles/tooltip-styles.js
  21. 45
      src/app/ui/tooltip.js
  22. 56
      src/lib/cmdInterpreterAPI.js
  23. 31
      src/remixAppManager.js
  24. 4
      src/universal-dapp.js
  25. 2
      test-browser/helpers/contracts.js
  26. 8
      test-browser/tests/compiling.js
  27. 36
      test-browser/tests/generalTests.js

@ -1,6 +1,6 @@
{
"name": "remix-ide",
"version": "v0.8.0-rc.1",
"version": "v0.8.0",
"description": "Minimalistic browser-based Solidity IDE",
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.8.1",
@ -68,7 +68,7 @@
},
"dependencies": {
"http-server": "^0.11.1",
"remix-plugin": "0.0.2-alpha.8",
"remix-plugin": "0.0.2-alpha.9",
"remixd": "0.1.8-alpha.6"
},
"repository": {
@ -156,7 +156,7 @@
"remix-ide": "./bin/remix-ide"
},
"scripts": {
"setupremix": "npm run linkremixdebug && npm run linkremixlib && npm run linkremixsolidity && npm run linkremixsimulator && npm run linkremixtests",
"setupremix": "npm run linkremixdebug && npm run linkremixlib && npm run linkremixsolidity && npm run linkremixanalyzer && npm run linkremixtests",
"pullremix": "git clone https://github.com/ethereum/remix",
"linkremixlib": "cd node_modules && rm -rf remix-lib && ln -s ../../remix/remix-lib remix-lib && cd ..",
"linkremixsolidity": "cd node_modules && rm -rf remix-solidity && ln -s ../../remix/remix-solidity remix-solidity && cd ..",

@ -171,7 +171,7 @@ module.exports = class LocalPlugin {
</div>
<div class="form-group">
<h6>Location in remix <small>(required)</small></h6>
${radioLocations('sidePanel', 'Swap Panel')}
${radioLocations('sidePanel', 'Side Panel')}
${radioLocations('mainPanel', 'Main Panel')}
${radioLocations('none', 'None')}
</form>`

@ -11,12 +11,9 @@ const css = csjs`
text-transform: uppercase;
white-space: nowrap;
}
.swapitTitle a{
cursor: help;
}
.swapitTitle i{
padding-left:4px;
font-size:10px;
padding-left: 6px;
font-size: 14px;
}
.swapitHeader {
height: 35px;
@ -67,7 +64,7 @@ export class SidePanel extends AbstractPanel {
const { profile } = this.store.getOne(this.active)
name = profile.displayName ? profile.displayName : profile.name
const docsRoot = 'https://remix.readthedocs.io/en/latest/'
docLink = profile.documentation ? yo`<a href="${docsRoot}${profile.documentation}" title="link to documentation" target="_blank"><sup><i aria-hidden="true" class="fas fa-book"></i></sup></a>` : ''
docLink = profile.documentation ? yo`<a href="${docsRoot}${profile.documentation}" title="link to documentation" target="_blank"><i aria-hidden="true" class="fas fa-book"></i></a>` : ''
}
return yo`

@ -47,6 +47,11 @@ module.exports = (contract, fileManager, cb, swarmVerifiedPublishCallBack) => {
var uploaded = []
async.eachSeries(sources, function (item, cb) {
swarmVerifiedPublish(item.content, item.hash, (error, result) => {
try {
item.hash = result.url.match('bzz-raw://(.+)')[1]
} catch (e) {
item.hash = '<Metadata inconsistency> - ' + item.fileName
}
if (!error && swarmVerifiedPublishCallBack) swarmVerifiedPublishCallBack(item)
item.output = result
uploaded.push(item)
@ -55,7 +60,19 @@ module.exports = (contract, fileManager, cb, swarmVerifiedPublishCallBack) => {
cb(error)
})
}, () => {
swarmVerifiedPublish(JSON.stringify(metadata), '', (error, result) => {
const metadataContent = JSON.stringify(metadata)
swarmVerifiedPublish(metadataContent, '', (error, result) => {
try {
contract.metadataHash = result.url.match('bzz-raw://(.+)')[1]
} catch (e) {
contract.metadataHash = '<Metadata inconsistency> - metadata.json'
}
if (!error && swarmVerifiedPublishCallBack) {
swarmVerifiedPublishCallBack({
content: metadataContent,
hash: contract.metadataHash
})
}
uploaded.push({
content: contract.metadata,
hash: contract.metadataHash,

@ -18,6 +18,10 @@ var css = csjs`
}
.txinput {
width: inherit;
font-size: small;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.txbuttons {
width: 100%;
@ -80,7 +84,14 @@ TxBrowser.prototype.render = function () {
var view = yo`<div class="${css.container}">
<div class="${css.txContainer}">
<div class="${css.txinputs} p-1 input-group">
<input value="${this.state.txNumber || ''}" class="form-control ${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction hash'} />
<input
value="${this.state.txNumber || ''}"
class="form-control m-0 ${css.txinput}"
id='txinput'
onkeyup=${function () { self.updateTxN(arguments[0]) }}
type='text'
placeholder=${'Transaction hash'}
/>
</div>
<div class="${css.txbuttons} btn-group p-1">
<button class='btn btn-primary btn-sm ${css.txbutton}' id='load' title='${this.state.debugging ? 'Stop' : 'Start'} debugging' onclick=${function () { self.submit() }}>${this.state.debugging ? 'Stop' : 'Start'} debugging</button>

@ -15,7 +15,6 @@ function CodeListView () {
this.event = new EventManager()
this.code
this.address
this.codeView
this.itemSelected
this.basicPanel = new DropdownPanel('Instructions', {json: false, displayContentOnly: true})
this.basicPanel.event.register('hide', () => {
@ -27,7 +26,8 @@ function CodeListView () {
}
CodeListView.prototype.render = function () {
return yo`<div id='asmcodes' >${this.basicPanel.render({height: style.instructionsList.height})}</div>`
this.view = yo`<div id='asmcodes' >${this.basicPanel.render({height: style.instructionsList.height})}</div>`
return this.view
}
CodeListView.prototype.indexChanged = function (index) {
@ -39,14 +39,15 @@ CodeListView.prototype.indexChanged = function (index) {
this.itemSelected.firstChild.removeAttribute('style')
}
}
this.itemSelected = this.codeView.children[index]
let codeView = this.view.querySelector('#asmitems')
this.itemSelected = codeView.children[index]
this.itemSelected.style.setProperty('background-color', 'var(--info)')
this.itemSelected.style.setProperty('color', 'var(--light)')
this.itemSelected.setAttribute('selected', 'selected')
if (this.itemSelected.firstChild) {
this.itemSelected.firstChild.setAttribute('style', 'margin-left: 2px')
}
this.codeView.scrollTop = this.itemSelected.offsetTop - parseInt(this.codeView.offsetTop)
codeView.scrollTop = this.itemSelected.offsetTop - parseInt(codeView.offsetTop)
}
CodeListView.prototype.reset = function () {
@ -59,8 +60,7 @@ CodeListView.prototype.changed = function (code, address, index) {
}
this.code = code
this.address = address
this.codeView = this.renderAssemblyItems()
this.basicPanel.setContent(this.codeView)
this.basicPanel.setContent(this.renderAssemblyItems())
this.indexChanged(index)
}

@ -219,7 +219,9 @@ class Editor {
*/
_getMode (path) {
let ext = path.indexOf('.') !== -1 ? /[^.]+/.exec(path) : null
if (ext) ext = path.replace(ext[0] + '.', '') // we get <ext>
if (ext) {
ext = path.replace(ext[0] + '.', '') // we get <ext>
} else ext = 'txt'
ext = ext.split('#')
if (!ext.length) return this.modes['txt']
ext = ext[0]

@ -41,13 +41,13 @@ class BasicReadOnlyExplorer {
}
set (path, content, cb) {
var unprefixedPath = this.removePrefix(path)
this.addReadOnly(unprefixedPath, content)
this.addReadOnly(path, content)
if (cb) cb()
return true
}
addReadOnly (path, content, rawPath) {
path = this.removePrefix(path)
try { // lazy try to format JSON
content = JSON.stringify(JSON.parse(content), null, '\t')
} catch (e) {}
@ -67,7 +67,7 @@ class BasicReadOnlyExplorer {
this.paths[this.type][split] = { isDirectory: folder }
this.files[path] = content
this.normalizedNames[rawPath] = path
this.event.trigger('fileAdded', [path, true])
this.event.trigger('fileAdded', [this.type + '/' + path, true])
return true
}

@ -158,7 +158,8 @@ function fileExplorer (localRegistry, files, menuItems) {
return yo`
<div class="${css.items}">
<label
class=${css.label}
title="${data.path}"
class="${css.label} ${!isRoot ? css.leaf : ''}"
data-path="${data.path}"
style="${isRoot ? 'font-weight:bold;' : ''}"
onkeydown=${editModeOff}

@ -135,9 +135,9 @@ class FileManager extends FileSystemApi {
if (this.currentRequest) {
let reject = false
let savedAsAnotherFile = false
let warnToaster
const actions = yo`<div class="container ml-1">
<button class="btn btn-primary btn-sm m-1" onclick=${(e) => { reject = true; e.target.innerHTML = 'Canceled'; warnToaster.hide() }}>Cancel</button>
let actions = (toaster) => {
return yo`<div class="container ml-1">
<button class="btn btn-primary btn-sm m-1" onclick=${(e) => { reject = true; e.target.innerHTML = 'Canceled'; toaster.hide() }}>Cancel</button>
<button class="btn btn-primary btn-sm m-1" onclick=${(e) => {
if (savedAsAnotherFile) return
savedAsAnotherFile = true
@ -145,10 +145,17 @@ class FileManager extends FileSystemApi {
this._setFileInternal(newPath, content)
this.switchFile(newPath)
e.target.innerHTML = 'Saved'
warnToaster.hide()
toaster.hide()
}}>Save As Copy</button>
</div>`
warnToaster = await toaster(yo`<div><i class="fas fa-exclamation-triangle text-info mr-1"></i><span class="text-primary">${this.currentRequest.from}</span> is modyfing <span class="text-primary">${path}</span></div>`, actions, { time: 4000 })
}
await toaster(yo`
<div>
<i class="fas fa-exclamation-triangle text-danger mr-1"></i>
<span>
${this.currentRequest.from}<span class="text-danger"> is modyfing </span>${path}
</span>
</div>`, actions, { time: 4000 })
if (reject) throw new Error(`set file operation on ${path} aborted by user.`)
if (savedAsAnotherFile) return
}

@ -93,7 +93,7 @@ function remixdDialog () {
return yo`
<div class=${css.dialog}>
<div class=${css.dialogParagraph}>Interact with your file system from Remix. Click connect and find shared folder in the Remix file explorer (under localhost).
Before you get started, check out <a target="_blank" href="https://remix.readthedocs.io/en/latest/tutorial_remixd_filesystem.html">Tutorial_remixd_filesystem</a>
Before you get started, check out the <a target="_blank" href="https://remix.readthedocs.io/en/latest/remixd.html">Remixd tutorial</a>.
to find out how to run Remixd.
</div>
<div class=${css.dialogParagraph}>Connection will start a session between <em>${window.location.href}</em> and your local file system <i>ws://127.0.0.1:65520</i>

@ -2,7 +2,13 @@ var csjs = require('csjs-inject')
var css = csjs`
.label {
margin-top : 4px
margin-top : 4px;
}
.leaf {
overflow : hidden;
text-overflow : ellipsis;
width : 90%;
margin-bottom : 0px;
}
.fileexplorer {
box-sizing : border-box;

@ -128,6 +128,9 @@ var css = csjs`
border-left : 1px solid var(--secondary)
height : 65%;
}
.listenOnNetworkLabel {
white-space : nowrap;
}
.pendingTx {
border-radius : 50%;
margin-right : 30px;

@ -152,7 +152,7 @@ class Terminal extends BaseApi {
title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you"
>
<label
class="form-check-label"
class="${css.listenOnNetworkLabel} form-check-label"
title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you"
for="listenNetworkCheck"
>
@ -168,8 +168,8 @@ class Terminal extends BaseApi {
`
self._view.term = yo`
<div class="${css.terminal_container}" onscroll=${throttle(reattach, 10)} onclick=${focusinput}>
<div style="
background-color: grey;
${self._components.autoCompletePopup.render()}
<div class="bg-secondary" style="
position: absolute;
height: 100%;
width: 100%;

@ -182,14 +182,20 @@ class CompileTab extends CompilerApi {
* @param {string[]} contractList Names of the compiled contracts
*/
contractSelection (contractList = [], sourceFile) {
return contractList.length !== 0
let selectEl = yo`
<select
onchange="${e => this.selectContract(e.target.value)}"
id="compiledContracts" class="custom-select"
>
${contractList.map((name) => yo`<option value="${name}">${name}</option>`)}
</select>
`
let result = contractList.length
? yo`<section class="${css.container} clearfix">
<!-- Select Compiler Version -->
<div class="navbar navbar-light bg-light input-group mb-3">
<label class="border-0 input-group-text" for="compiledContracts">Contract</label>
<select onchange="${e => this.selectContract(e.target.value)}" onload="${e => { this.selectedContract = e.value }}" id="compiledContracts" class="custom-select">
${contractList.map((name) => yo`<option value="${name}">${name}</option>`)}
</select>
<label class="border-0 input-group-text" for="compiledContracts">Contract</label>
${selectEl}
</div>
<article class="${css.compilerArticle}">
@ -220,6 +226,13 @@ class CompileTab extends CompilerApi {
: yo`<section class="${css.container} clearfix"><article class="${css.compilerArticle}">
<span class="alert alert-warning" role="alert">No Contract Compiled Yet</span>
</article></section>`
if (contractList.length) {
this.selectedContract = selectEl.value
} else {
delete this.selectedContract
}
return result
}
// TODO : Add success alert when compilation succeed
@ -259,7 +272,7 @@ class CompileTab extends CompilerApi {
modalDialogCustom.alert(yo`<span>Metadata published successfully.<br> <pre>${result}</pre> </span>`)
}
}, (item) => { // triggered each time there's a new verified publish (means hash correspond)
this.swarmfileProvider.addReadOnly(item.hash, item.content)
this.swarmfileProvider.addReadOnly('swarm/' + item.hash, item.content)
})
}
}

@ -30,8 +30,8 @@ class Settings {
this.networkcallid = 0
}
changeExecutionContext (context, cb) {
return executionContext.executionContextChange(context, null, cb)
changeExecutionContext (context, confirmCb, infoCb, cb) {
return executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
}
setProviderFromEndpoint (target, context, cb) {

@ -97,7 +97,7 @@ class SettingsUI {
<div class=${css.account}>
<select name="txorigin" class="form-control ${css.select}" id="txorigin"></select>
${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)}
<i id="remixRunSignMsg" class="fas fa-edit ${css.icon}" aria-hiden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
<i id="remixRunSignMsg" class="fas fa-edit ${css.icon}" aria-hidden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
</div>
</div>
`
@ -143,10 +143,11 @@ class SettingsUI {
setInterval(() => {
this.updateNetwork()
this.fillAccountsList()
}, 5000)
this.el = el
this.fillAccountsList()
return el
}
@ -198,7 +199,6 @@ class SettingsUI {
this.selectExEnv.value = this.settings.getProvider()
this.event.trigger('clearInstance', [])
this.updateNetwork()
this.fillAccountsList()
this.updatePlusButton()
}
@ -310,6 +310,7 @@ class SettingsUI {
let network = this._deps.networkModule.getNetworkProvider
this.netUI.innerHTML = (network() !== 'vm') ? `${name} (${id || '-'}) network` : ''
})
this.fillAccountsList()
}
// TODO: unclear what's the goal of accountListCallId, feels like it can be simplified

@ -3,8 +3,6 @@ var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
var Commands = require('../constants/commands')
var modal = require('./modaldialog.js')
// -------------- styling ----------------------
var css = require('./styles/auto-complete-popup-styles')
@ -27,26 +25,23 @@ class AutoCompletePopup {
self.data = {
_options: []
}
self._components = {
modal: null
}
self._view = {}
self._components = {}
self._view
self._startingElement = 0
self._elementsToShow = 4
self._selectedElement = 0
this.extraCommands = []
this.render()
this.extendAutocompletion()
}
render () {
var self = this
self._view.autoComplete = yo`
<div class="${css.popup}">
let autoComplete = yo`
<div class="${css.popup} alert alert-secondary">
<div>
${self.data._options.map((item, index) => {
return yo`
<div class="${css.autoCompleteItem} ${css.listHandlerHide} item ${self._selectedElement === index ? 'bg-secondary' : ''}">
<div class="${css.autoCompleteItem} ${css.listHandlerHide} item ${self._selectedElement === index ? 'border border-primary' : ''}">
<div value=${index} onclick=${(event) => { self.handleSelect(event.srcElement.innerText) }}>
${getKeyOf(item)}
</div>
@ -62,22 +57,19 @@ class AutoCompletePopup {
</div>
</div>
`
function setUpPopUp () {
handleOpenPopup()
handleListSize()
function setUpPopUp (autoComplete) {
handleOpenPopup(autoComplete)
handleListSize(autoComplete)
}
function handleOpenPopup () {
if (self.data._options.length > 0) {
self._view.autoComplete.style.display = 'block'
self._components.modal = modal('', self._view.autoComplete, {label: null}, {label: null}, null, { class: css.modalContent, hideClose: true })
}
function handleOpenPopup (autoComplete) {
autoComplete.style.display = self.data._options.length > 0 ? 'block' : 'none'
}
function handleListSize () {
function handleListSize (autoComplete) {
if (self.data._options.length >= self._startingElement) {
for (let i = self._startingElement; i < (self._elementsToShow + self._startingElement); i++) {
let el = self._view.autoComplete.querySelectorAll('.item')[i]
let el = autoComplete.querySelectorAll('.item')[i]
if (el) {
el.classList.remove(css.listHandlerHide)
el.classList.add(css.listHandlerShow)
@ -85,10 +77,9 @@ class AutoCompletePopup {
}
}
}
setUpPopUp()
return self._view
setUpPopUp(autoComplete)
if (!this._view) this._view = autoComplete
return autoComplete
}
handleSelect (text) {
@ -189,8 +180,7 @@ class AutoCompletePopup {
removeAutoComplete () {
if (!this.isOpen) return
this._view.autoComplete.style.display = 'none'
if (this._components.modal) this._components.modal.cancelListener()
this._view.style.display = 'none'
this.isOpen = false
this.data._options = []
this._startingElement = 0

@ -2,6 +2,7 @@ var csjs = require('csjs-inject')
var css = csjs`
.popup {
position : absolute;
text-align : left;
display : none;
width : 100%;
@ -9,6 +10,8 @@ var css = csjs`
font-size : 10px;
overflow : auto;
padding-bottom : 13px;
z-index : 2;
bottom : 1.7em;
}
.autoCompleteItem {

@ -15,6 +15,7 @@ var css = csjs`
font-size: 14px;
text-align: center;
bottom: 0;
flex-direction: row;
}
@-webkit-keyframes animatebottom {
0% {bottom: -300px}

@ -1,3 +1,4 @@
/* global Element */
var yo = require('yo-yo')
var css = require('./styles/tooltip-styles')
var modal = require('./modal-dialog-custom')
@ -5,11 +6,12 @@ var modal = require('./modal-dialog-custom')
/**
* Open a tooltip
* @param {string} tooltipText The text shown by the tooltip
* @param {HTMLElement} [action] An HTMLElement to display for action
* @param {function} [action] Returns An HTMLElement to display for action
*/
module.exports = function addTooltip (tooltipText, action, opts) {
action = action || function () { return yo`<div></div>` }
let t = new Toaster()
return t.render(tooltipText, action, opts)
return t.render(tooltipText, action(t), opts)
}
class Toaster {
@ -23,15 +25,44 @@ class Toaster {
}
render (tooltipText, action, opts) {
opts = defaultOptions(opts)
let canShorten = true
if (tooltipText instanceof Element) {
canShorten = false
} else {
if (typeof tooltipText === 'object') {
if (tooltipText.message) {
tooltipText = tooltipText.message
} else {
try {
tooltipText = JSON.stringify(tooltipText)
} catch (e) {
}
}
}
}
return new Promise((resolve, reject) => {
const shortTooltipText = tooltipText.length > 201 ? tooltipText.substring(0, 200) + '...' : tooltipText
const shortTooltipText = (canShorten && tooltipText.length > 201) ? tooltipText.substring(0, 200) + '...' : tooltipText
let button = tooltipText.length > 201 ? yo`
<button class="btn btn-secondary btn-sm mx-3" style="white-space: nowrap;" onclick=${() => { modal.alert(tooltipText) }}>Show full message</button>
` : ``
this.tooltip = yo`
<div class="${css.tooltip} alert alert-info" onmouseenter=${() => { over() }} onmouseleave=${() => { out() }}>
<span>${shortTooltipText}<button class="btn btn-secondary btn-sm" onclick=${() => { modal.alert(tooltipText) }}>show full message</button></span>
${action}
</div>`
<div class="${css.tooltip} alert alert-info p-2" onmouseenter=${() => { over() }} onmouseleave=${() => { out() }}>
<span class="px-2">
${shortTooltipText}
${button}
${action}
</span>
<span style="align-self: baseline;">
<button class="fas fa-times btn-info mx-1 p-0" onclick=${() => {
this.hide()
over()
resolve()
}}></button>
</span>
</div>`
let timeOut = () => {
return setTimeout(() => {
if (this.id) {

@ -4,6 +4,7 @@ var async = require('async')
var remixLib = require('remix-lib')
var EventManager = require('../lib/events')
var CompilerImport = require('../app/compiler/compiler-imports')
var executionContext = require('../execution-context')
var toolTip = require('../app/ui/tooltip')
var globalRegistry = require('../global/registry')
@ -20,6 +21,7 @@ class CmdInterpreterAPI {
self._components.registry = localRegistry || globalRegistry
self._components.terminal = terminal
self._components.sourceHighlighter = new SourceHighlighter()
self._components.fileImport = new CompilerImport()
self._deps = {
app: self._components.registry.get('app').api,
fileManager: self._components.registry.get('filemanager').api,
@ -141,28 +143,40 @@ class CmdInterpreterAPI {
}
loadurl (url, cb) {
const self = this
self._deps.app.importExternal(url, (err, content) => {
if (err) {
toolTip(`Unable to load ${url}: ${err}`)
if (cb) cb(err)
} else {
try {
content = JSON.parse(content)
async.eachOfSeries(content.sources, (value, file, callbackSource) => {
var url = value.urls[0] // @TODO retrieve all other contents ?
self._deps.app.importExternal(url, (error, content) => {
if (error) {
toolTip(`Cannot retrieve the content of ${url}: ${error}`)
}
callbackSource()
self._components.fileImport.import(url,
(loadingMsg) => { toolTip(loadingMsg) },
(err, content, cleanUrl, type, url) => {
if (err) {
toolTip(`Unable to load ${url}: ${err}`)
if (cb) cb(err)
} else {
self._deps.fileManager.setFile(type + '/' + cleanUrl, content)
try {
content = JSON.parse(content)
async.eachOfSeries(content.sources, (value, file, callbackSource) => {
var url = value.urls[0] // @TODO retrieve all other contents ?
self._components.fileImport.import(url,
(loadingMsg) => { toolTip(loadingMsg) },
async (error, content, cleanUrl, type, url) => {
if (error) {
toolTip(`Cannot retrieve the content of ${url}: ${error}`)
return callbackSource(`Cannot retrieve the content of ${url}: ${error}`)
} else {
try {
await self._deps.fileManager.setFile(type + '/' + cleanUrl, content)
callbackSource()
} catch (e) {
callbackSource(e.message)
}
}
})
}, (error) => {
if (cb) cb(error)
})
}, (error) => {
if (cb) cb(error)
})
} catch (e) {}
if (cb) cb()
}
})
} catch (e) {}
if (cb) cb()
}
})
}
setproviderurl (url, cb) {
executionContext.setProviderFromEndpoint(url, 'web3', (error) => {

@ -84,15 +84,36 @@ export class RemixAppManager extends AppManagerApi {
icon: 'data:image/png;base64,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',
location: 'mainPanel'
}
var mythx = {
name: 'remythx',
displayName: 'MythX',
description: 'Security analysis of smart contracts by using MythX',
var etherscan = {
name: 'etherscan',
displayName: 'Etherscan - Contract verification',
events: [],
methods: [],
notifications: {
'solidity': ['compilationFinished']
},
url: 'https://remix-etherscan-plugin.surge.sh',
description: 'Verify Solidity contract code using Etherscan API',
icon: 'data:image/png;base64,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',
location: 'sidePanel'
}
var ethdoc = {
name: 'solidityDocMd',
displayName: 'Solidity documentation generator',
events: [],
methods: [],
notifications: {
'solidity': ['compilationFinished']
},
url: 'https://remix-ethdoc-plugin.surge.sh',
description: 'Generate Solidity documentation (as md) using Natspec',
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIxMDI0IiB3aWR0aD0iMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOTUwLjE1NCAxOTJINzMuODQ2QzMzLjEyNyAxOTIgMCAyMjUuMTI2OTk5OTk5OTk5OTUgMCAyNjUuODQ2djQ5Mi4zMDhDMCA3OTguODc1IDMzLjEyNyA4MzIgNzMuODQ2IDgzMmg4NzYuMzA4YzQwLjcyMSAwIDczLjg0Ni0zMy4xMjUgNzMuODQ2LTczLjg0NlYyNjUuODQ2QzEwMjQgMjI1LjEyNjk5OTk5OTk5OTk1IDk5MC44NzUgMTkyIDk1MC4xNTQgMTkyek01NzYgNzAzLjg3NUw0NDggNzA0VjUxMmwtOTYgMTIzLjA3N0wyNTYgNTEydjE5MkgxMjhWMzIwaDEyOGw5NiAxMjggOTYtMTI4IDEyOC0wLjEyNVY3MDMuODc1ek03NjcuMDkxIDczNS44NzVMNjA4IDUxMmg5NlYzMjBoMTI4djE5Mmg5Nkw3NjcuMDkxIDczNS44NzV6Ii8+PC9zdmc+',
location: 'sidePanel'
}
var mythx = {
name: 'remythx',
displayName: 'MythX',
description: 'Security analysis of smart contracts by using MythX',
url: 'https://remythx.xyz',
icon: 'https://remythx.xyz/logo.png',
location: 'sidePanel'
@ -100,6 +121,8 @@ export class RemixAppManager extends AppManagerApi {
return [
new Plugin(pipeline),
new Plugin(vyper),
new Plugin(etherscan),
new Plugin(ethdoc),
new Plugin(mythx)
]
}

@ -33,7 +33,7 @@ module.exports = class UniversalDApp extends UdappApi {
executionContext.detectNetwork(cb)
},
personalMode: () => {
return this._deps.config.get('settings/personal-mode')
return executionContext.getProvider() === 'web3' ? this._deps.config.get('settings/personal-mode') : false
}
}
this.txRunner = new TxRunner({}, this._txRunnerAPI)
@ -67,7 +67,7 @@ module.exports = class UniversalDApp extends UdappApi {
executionContext.detectNetwork(cb)
},
personalMode: () => {
return this._deps.config.get('settings/personal-mode')
return executionContext.getProvider() === 'web3' ? this._deps.config.get('settings/personal-mode') : false
}
})
this.txRunner.event.register('transactionBroadcasted', (txhash) => {

@ -172,7 +172,9 @@ function scrollInto (target) {
function signMsg (browser, msg, cb) {
let hash, signature
browser
.waitForElementPresent('i[id="remixRunSignMsg"]')
.click('i[id="remixRunSignMsg"]')
.waitForElementPresent('textarea[id="prompt_text"]')
.setValue('textarea[id="prompt_text"]', msg, () => {
browser.modalFooterOKClick().perform(
(client, done) => {

@ -160,8 +160,8 @@ function testInputValues (browser, callback) {
var sources = [
{'browser/Untitled.sol': {content: `
contract TestContract { function f() public returns (uint) { return 8; }
function g() public returns (uint, string memory, bool, uint) {
contract TestContract { function f() public returns (uint) { return 8; }
function g() public returns (uint, string memory, bool, uint) {
uint payment = 345;
bool payed = true;
string memory comment = "comment_comment_";
@ -176,7 +176,7 @@ var sources = [
_i = -345;
_a = msg.sender;
}
function retunValues2 () public returns (byte _b, bytes2 _b2, bytes3 _b3, bytes memory _blit, bytes5 _b5, bytes6 _b6, string memory _str, bytes7 _b7, bytes22 _b22, bytes32 _b32) {
_b = 0x12;
_b2 = 0x1223;
@ -188,7 +188,7 @@ var sources = [
_blit = hex"123498";
_str = "this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string";
}
function retunValues3 () public returns (ActionChoices _en, int[5][] memory _a1) {
_en = ActionChoices.GoStraight;
int[5][] memory a = new int[5][](3);

@ -34,7 +34,7 @@ function runTests (browser) {
async.waterfall([function (callback) { callback(null, browser) },
testSimpleContract,
testSuccessImport,
testFailedImport, /* testGitHubImport */
testFailedImport, /* testGitHubImport, */
addDeployLibTestFile,
testAutoDeployLib,
testManualDeployLib,
@ -168,22 +168,28 @@ function testSignature (browser, callback) {
contractHelper.signMsg(browser, 'test message', (h, s) => {
hash = h
signature = s
browser.assert.ok(typeof hash.value === 'string', 'type of hash.value must be String')
browser.assert.ok(typeof signature.value === 'string', 'type of signature.value must be String')
contractHelper.addFile(browser, 'signMassage.sol', sources[6]['browser/signMassage.sol'], () => {
contractHelper.switchFile(browser, 'browser/signMassage.sol', () => {
contractHelper.selectContract(browser, 'ECVerify', () => { // deploy lib
contractHelper.createContract(browser, '', () => {
browser.waitForElementPresent('.instance:nth-of-type(4)')
.click('.instance:nth-of-type(4) > div > button')
.clickFunction('ecrecovery - call', {types: 'bytes32 hash, bytes sig', values: `"${hash.value}","${signature.value}"`}).perform(
() => {
contractHelper.verifyCallReturnValue(
browser,
'0x08970fed061e7747cd9a38d680a601510cb659fb',
['0: address: 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c'],
() => { callback(null, browser) }
)
}
)
const instanceSelector = '.instance:nth-of-type(4)'
browser.waitForElementPresent(instanceSelector)
.click(instanceSelector + ' > div > button')
.getAttribute(instanceSelector, 'id', (result) => {
// skip 'instance' part of e.g. 'instance0x692a70d2e424a56d2c6c27aa97d1a86395877b3a'
const address = result.value.slice('instance'.length)
browser.clickFunction('ecrecovery - call', {types: 'bytes32 hash, bytes sig', values: `"${hash.value}","${signature.value}"`}).perform(
() => {
contractHelper.verifyCallReturnValue(
browser,
address,
['0: address: 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c'],
() => { callback(null, browser) }
)
})
})
})
})
})
@ -347,13 +353,13 @@ var sources = [
'browser/Untitled5.sol': {content: `library lib {
function getInt () public view returns (uint) {
return 45;
}
}
}
contract test {
function get () public view returns (uint) {
return lib.getInt();
}
}
}`}
},
{

Loading…
Cancel
Save