diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts
index 19918de0c4..e55ae8d6fd 100644
--- a/apps/remix-ide-e2e/src/tests/debugger.test.ts
+++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts
@@ -205,6 +205,7 @@ module.exports = {
.clickLaunchIcon('debugger')
.waitForElementVisible('*[data-id="slider"]')
.goToVMTraceStep(154)
+ .scrollInto('*[data-id="stepdetail"]')
.waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n154', 60000)
},
diff --git a/apps/remix-ide-e2e/src/tests/editor_error_marker.test.ts b/apps/remix-ide-e2e/src/tests/editor_error_marker.test.ts
new file mode 100644
index 0000000000..8d8cba54e0
--- /dev/null
+++ b/apps/remix-ide-e2e/src/tests/editor_error_marker.test.ts
@@ -0,0 +1,84 @@
+'use strict'
+
+import { NightwatchBrowser } from 'nightwatch'
+import init from '../helpers/init'
+
+module.exports = {
+
+ before: function (browser: NightwatchBrowser, done: VoidFunction) {
+ init(browser, done, 'http://127.0.0.1:8080', true)
+ },
+ 'Should add error marker': function (browser: NightwatchBrowser) {
+ browser
+ .openFile('contracts')
+ .openFile('contracts/1_Storage.sol')
+ .addFile('scripts/adderror.ts', {content: addErrorMarker})
+ .pause(4000)
+ .executeScriptInTerminal('remix.exeCurrent()')
+ .pause(4000)
+ .openFile('contracts/1_Storage.sol')
+ .useXpath()
+ .waitForElementVisible("//*[@class='cdr squiggly-error']")
+ .waitForElementVisible("//*[@class='cdr squiggly-warning']")
+ },
+ 'Should clear error marker': function (browser: NightwatchBrowser) {
+ browser
+ .useCss()
+ .addFile('scripts/clear.ts', {content: clearMarkers})
+ .pause(4000)
+ .executeScriptInTerminal('remix.exeCurrent()')
+ .pause(4000)
+ .openFile('contracts/1_Storage.sol')
+ .useXpath()
+ .waitForElementNotPresent("//*[@class='cdr squiggly-error']")
+ .waitForElementNotPresent("//*[@class='cdr squiggly-warning']")
+ }
+}
+
+const clearMarkers =`
+(async () => {
+ await remix.call('editor', 'clearErrorMarkers' as any, ['contracts/1_Storage.sol'])
+})()`
+
+const addErrorMarker = `
+(async () => {
+
+
+ let errors = [
+ {
+ position: {
+ start: {
+ line: 10,
+ column: 1,
+ },
+ end: {
+ line: 10,
+ column: 10
+ }
+ },
+ message: 'testing',
+ severity: 'error',
+ file: 'contracts/1_Storage.sol'
+ },
+ {
+ position: {
+ start: {
+ line: 18,
+ column: 1,
+ },
+ end: {
+ line: 18,
+ column: 10
+ }
+ },
+ message: 'testing2',
+ severity: 'warning',
+ file: 'contracts/1_Storage.sol'
+ },
+ ]
+
+
+ await remix.call('editor', 'addErrorMarker' as any, errors)
+
+
+})()`
\ No newline at end of file
diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts
index 5bf3b34d5d..21832de532 100644
--- a/apps/remix-ide-e2e/src/tests/gist.test.ts
+++ b/apps/remix-ide-e2e/src/tests/gist.test.ts
@@ -9,10 +9,11 @@ const testData = {
// 99266d6da54cc12f37f11586e8171546c7700d67
module.exports = {
+ '@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
- UploadToGists: function (browser: NightwatchBrowser) {
+ 'UploadToGists #group1': function (browser: NightwatchBrowser) {
/*
- set the access token
- publish to gist
@@ -68,7 +69,7 @@ module.exports = {
*/
},
- 'Load Gist Modal': function (browser: NightwatchBrowser) {
+ 'Load Gist Modal #group1': function (browser: NightwatchBrowser) {
browser.clickLaunchIcon('home')
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('filePanel')
@@ -84,7 +85,7 @@ module.exports = {
.modalFooterCancelClick('gisthandler')
},
- 'Display Error Message For Invalid Gist ID': function (browser: NightwatchBrowser) {
+ 'Display Error Message For Invalid Gist ID #group1': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
@@ -101,7 +102,7 @@ module.exports = {
.modalFooterOKClick('gisthandler')
},
- 'Display Error Message For Missing Gist Token When Publishing': function (browser: NightwatchBrowser) {
+ 'Display Error Message For Missing Gist Token When Publishing #group1': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
@@ -125,7 +126,7 @@ module.exports = {
.click('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
},
- 'Import From Gist For Valid Gist ID': function (browser: NightwatchBrowser) {
+ 'Import From Gist For Valid Gist ID #group2': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('settings')
@@ -140,6 +141,7 @@ module.exports = {
})
.setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId)
.modalFooterOKClick('gisthandler')
+ .pause(10000)
.openFile(`gist-${testData.validGistId}/README.txt`)
.waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/README.txt']`)
.assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt')
diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts
index f944b453f9..baf0639cc5 100644
--- a/apps/remix-ide-e2e/src/tests/terminal.test.ts
+++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts
@@ -217,13 +217,42 @@ module.exports = {
.addFile('scripts/log_tx_block.js', { content: scriptBlockAndTransaction } )
.pause(1000)
.executeScriptInTerminal('remix.execute(\'scripts/log_tx_block.js\')')
- .pause(10000)
// check if the input of the transaction is being logged (web3 call)
- .journalChildIncludes('0x775526410000000000000000000000000000000000000000000000000000000000000060464c0335b2f1609abd9de25141c0a3b49db516fc7375970dc737c32b986e88e3000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000000602926b30b10e7a514d92bc71e085f5bff2687fac2856ae43ef7621bf1756fa370516d310bec5727543089be9a4d5f68471174ee528e95a2520b0ca36c2b6c6eb0000000000000000000000000000000000000000000000000000000000046f49036f5e4ea4dd042801c8841e3db8e654124305da0f11824fc1db60c405dbb39f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
+ .waitForElementContainsText('*[data-id="terminalJournal"]', '0x775526410000000000000000000000000000000000000000000000000000000000000060464c0335b2f1609abd9de25141c0a3b49db516fc7375970dc737c32b986e88e3000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000000602926b30b10e7a514d92bc71e085f5bff2687fac2856ae43ef7621bf1756fa370516d310bec5727543089be9a4d5f68471174ee528e95a2520b0ca36c2b6c6eb0000000000000000000000000000000000000000000000000000000000046f49036f5e4ea4dd042801c8841e3db8e654124305da0f11824fc1db60c405dbb39f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 120000)
// check if the logsBloom is being logged (web3 call)
- .journalChildIncludes('0x00000000000000000000000000100000000000000000020000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000040000000060000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001')
+ .waitForElementContainsText('*[data-id="terminalJournal"]', '0x00000000000000000000000000100000000000000000020000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000040000000060000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001', 120000)
// check if the logsBloom is being logged (ethers.js call)
- .journalChildIncludes('"hex":"0x025cd8"')
+ .waitForElementContainsText('*[data-id="terminalJournal"]', '"hex":"0x025cd8"', 120000)
+ },
+
+ 'Should listen on all transactions #group8': function (browser: NightwatchBrowser) {
+ browser
+ .clickLaunchIcon('udapp') // connect to mainnet
+ .switchEnvironment('External Http Provider')
+ .waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]')
+ .execute(() => {
+ (document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus()
+ }, [], () => {})
+ .setValue('[data-id="modalDialogCustomPromp"]', 'https://rpc.archivenode.io/e50zmkroshle2e2e50zm0044i7ao04ym')
+ .modalFooterOKClick('basic-http-provider')
+ .click('[data-id="terminalClearConsole"]') // clear the console
+ .click('[data-id="listenNetworkCheckInput"]') // start to listen
+ .waitForElementContainsText('*[data-id="terminalJournal"]', 'from:', 200000)
+ .waitForElementContainsText('*[data-id="terminalJournal"]', 'to:', 200000)
+ .click('[data-id="terminalClearConsole"]') // clear the console
+ .waitForElementContainsText('*[data-id="terminalJournal"]', 'from:', 200000)
+ .waitForElementContainsText('*[data-id="terminalJournal"]', 'to:', 200000)
+ .click('[data-id="listenNetworkCheckInput"]') // stop to listen
+ .pause(30000)
+ .click('[data-id="terminalClearConsole"]') // clear the console
+ .pause(5000)
+ .click('[data-id="terminalClearConsole"]') // clear the console
+ .pause(20000)
+ .execute(function () {
+ return (document.querySelector('[data-id="terminalJournal"]') as any).innerText
+ }, [], function (result) {
+ browser.assert.equal(result.value, '', 'terminal log should be empty')
+ })
}
}
diff --git a/apps/remix-ide-e2e/src/tests/vyper_api.ts b/apps/remix-ide-e2e/src/tests/vyper_api.ts
index f168372963..bb0afc3859 100644
--- a/apps/remix-ide-e2e/src/tests/vyper_api.ts
+++ b/apps/remix-ide-e2e/src/tests/vyper_api.ts
@@ -21,25 +21,30 @@ module.exports = {
.frame(0)
},
- 'Should add the Ballot.vy #group1': function (browser: NightwatchBrowser) {
- browser.click('button[data-id="add-ballot"]')
+ 'Should clone the Vyper repo #group1': function (browser: NightwatchBrowser) {
+ browser.click('button[data-id="add-repository"]')
.frameParent()
- .openFile('ballot.vy')
+ .waitForElementContainsText('*[data-shared="tooltipPopup"]', 'Vyper repository cloned', 30000)
+ .openFile('examples')
+ .openFile('examples/auctions')
+ .openFile('examples/auctions/blind_auction.vy')
},
- 'Compile ballot.vy should error #group1': function (browser: NightwatchBrowser) {
+ 'Compile blind_auction should success #group1': function (browser: NightwatchBrowser) {
browser.clickLaunchIcon('vyper')
// @ts-ignore
.frame(0)
.click('[data-id="remote-compiler"]')
.click('[data-id="compile"]')
- .assert.containsText('[data-id="error-message"]', 'unexpected indent')
+ .waitForElementVisible('[data-id="copy-abi"]')
},
- 'Compile test contract should success #group1': function (browser: NightwatchBrowser) {
+ 'Compile test contract and deploy to remix VM #group1': function (browser: NightwatchBrowser) {
let contractAddress
browser
.frameParent()
+ .clickLaunchIcon('filePanel')
+ .switchWorkspace('default_workspace')
.addFile('test.vy', { content: testContract })
.clickLaunchIcon('vyper')
// @ts-ignore
diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js
index 34b9c172e5..f46b1b2d21 100644
--- a/apps/remix-ide/src/app/editor/editor.js
+++ b/apps/remix-ide/src/app/editor/editor.js
@@ -13,7 +13,7 @@ const profile = {
name: 'editor',
description: 'service - editor',
version: packageJson.version,
- methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition']
+ methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition', 'addErrorMarker', 'clearErrorMarkers']
}
class Editor extends Plugin {
@@ -504,6 +504,15 @@ class Editor extends Plugin {
}
}
+ // error markers
+ async addErrorMarker (error){
+ this.api.addErrorMarker(error)
+ }
+
+ async clearErrorMarkers(sources){
+ this.api.clearErrorMarkers(sources)
+ }
+
/**
* Clears all the annotations for the given @arg filePath, the plugin name is retrieved from the context, if none is given, the current sesssion is used.
* An annotation has the following shape:
diff --git a/apps/remix-ide/src/app/tabs/debugger-tab.js b/apps/remix-ide/src/app/tabs/debugger-tab.js
index a06db0c508..5e62bd93d4 100644
--- a/apps/remix-ide/src/app/tabs/debugger-tab.js
+++ b/apps/remix-ide/src/app/tabs/debugger-tab.js
@@ -3,7 +3,7 @@ import { DebuggerApiMixin } from '@remixproject/debugger-plugin' // eslint-disab
import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
-import * as remixBleach from '../../lib/remixBleach'
+import { bleach } from '@remix-ui/helper'
import { compilationFinishedToastMsg, compilingToastMsg, localCompilationToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper'
const css = require('./styles/debugger-tab-styles')
@@ -51,7 +51,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => {
this.call('notification', 'toast', sourceVerificationNotAvailableToastMsg())
})
- return
+ return
}
showMessage (title, message) {
@@ -59,7 +59,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
this.call('notification', 'alert', {
id: 'debuggerTabShowMessage',
title,
- message: remixBleach.sanitize(message)
+ message: bleach.sanitize(message)
})
} catch (e) {
console.log(e)
diff --git a/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js b/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js
index 6a15d2cf56..3fb7add424 100644
--- a/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js
+++ b/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js
@@ -1,9 +1,6 @@
var csjs = require('csjs-inject')
const css = csjs`
- .debuggerTabView {
- padding: 2%;
- }
.debugger {
margin-bottom: 1%;
}
diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css
index f95afd68ec..98d4b409c3 100644
--- a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css
+++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css
@@ -34,6 +34,7 @@
--dark:#343a40;
--body-bg: #fff;
--text-bg-mark: #fcf8e3;
+ --custom-select: #fff;
--breakpoint-xs:0;
--breakpoint-sm:576px;
--breakpoint-md:768px;
@@ -435,25 +436,25 @@ pre code {
.container,.container-sm {
max-width:540px
}
-
+
}
@media (min-width:768px) {
.container,.container-md,.container-sm {
max-width:720px
}
-
+
}
@media (min-width:992px) {
.container,.container-lg,.container-md,.container-sm {
max-width:960px
}
-
+
}
@media (min-width:1200px) {
.container,.container-lg,.container-md,.container-sm,.container-xl {
max-width:1140px
}
-
+
}
.row {
display:-ms-flexbox;
@@ -873,7 +874,7 @@ pre code {
.offset-sm-11 {
margin-left:91.666667%
}
-
+
}
@media (min-width:768px) {
.col-md {
@@ -1075,7 +1076,7 @@ pre code {
.offset-md-11 {
margin-left:91.666667%
}
-
+
}
@media (min-width:992px) {
.col-lg {
@@ -1277,7 +1278,7 @@ pre code {
.offset-lg-11 {
margin-left:91.666667%
}
-
+
}
@media (min-width:1200px) {
.col-xl {
@@ -1479,7 +1480,7 @@ pre code {
.offset-xl-11 {
margin-left:91.666667%
}
-
+
}
.table {
width:100%;
@@ -1662,7 +1663,7 @@ pre code {
.table-responsive-sm>.table-bordered {
border:0
}
-
+
}
@media (max-width:767.98px) {
.table-responsive-md {
@@ -1674,7 +1675,7 @@ pre code {
.table-responsive-md>.table-bordered {
border:0
}
-
+
}
@media (max-width:991.98px) {
.table-responsive-lg {
@@ -1686,7 +1687,7 @@ pre code {
.table-responsive-lg>.table-bordered {
border:0
}
-
+
}
@media (max-width:1199.98px) {
.table-responsive-xl {
@@ -1698,7 +1699,7 @@ pre code {
.table-responsive-xl>.table-bordered {
border:0
}
-
+
}
.table-responsive {
display:block;
@@ -1728,7 +1729,7 @@ pre code {
.form-control {
transition:none
}
-
+
}
.form-control::-ms-expand {
background-color:transparent;
@@ -2114,7 +2115,7 @@ textarea.form-control {
.form-inline .custom-control-label {
margin-bottom:0
}
-
+
}
.btn {
display:inline-block;
@@ -2138,7 +2139,7 @@ textarea.form-control {
.btn {
transition:none
}
-
+
}
.btn:hover {
color:#495057;
@@ -2626,7 +2627,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.fade {
transition:none
}
-
+
}
.fade:not(.show) {
opacity:0
@@ -2644,7 +2645,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.collapsing {
transition:none
}
-
+
}
.dropdown,.dropleft,.dropright,.dropup {
position:relative
@@ -2701,7 +2702,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0;
left:auto
}
-
+
}
@media (min-width:768px) {
.dropdown-menu-md-left {
@@ -2712,7 +2713,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0;
left:auto
}
-
+
}
@media (min-width:992px) {
.dropdown-menu-lg-left {
@@ -2723,7 +2724,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0;
left:auto
}
-
+
}
@media (min-width:1200px) {
.dropdown-menu-xl-left {
@@ -2734,7 +2735,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0;
left:auto
}
-
+
}
.dropup .dropdown-menu {
top:auto;
@@ -3190,7 +3191,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.custom-switch .custom-control-label::after {
transition:none
}
-
+
}
.custom-switch .custom-control-input:checked~.custom-control-label::after {
background-color:#fff;
@@ -3356,7 +3357,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
-webkit-transition:none;
transition:none
}
-
+
}
.custom-range::-webkit-slider-thumb:active {
background-color:#cfeaf9
@@ -3386,7 +3387,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
-moz-transition:none;
transition:none
}
-
+
}
.custom-range::-moz-range-thumb:active {
background-color:#cfeaf9
@@ -3418,7 +3419,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
-ms-transition:none;
transition:none
}
-
+
}
.custom-range::-ms-thumb:active {
background-color:#cfeaf9
@@ -3463,7 +3464,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.custom-control-label::before,.custom-file-label,.custom-select {
transition:none
}
-
+
}
.nav {
display:-ms-flexbox;
@@ -3629,7 +3630,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
padding-right:0;
padding-left:0
}
-
+
}
@media (min-width:576px) {
.navbar-expand-sm {
@@ -3662,14 +3663,14 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.navbar-expand-sm .navbar-toggler {
display:none
}
-
+
}
@media (max-width:767.98px) {
.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl {
padding-right:0;
padding-left:0
}
-
+
}
@media (min-width:768px) {
.navbar-expand-md {
@@ -3702,14 +3703,14 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.navbar-expand-md .navbar-toggler {
display:none
}
-
+
}
@media (max-width:991.98px) {
.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl {
padding-right:0;
padding-left:0
}
-
+
}
@media (min-width:992px) {
.navbar-expand-lg {
@@ -3742,14 +3743,14 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.navbar-expand-lg .navbar-toggler {
display:none
}
-
+
}
@media (max-width:1199.98px) {
.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl {
padding-right:0;
padding-left:0
}
-
+
}
@media (min-width:1200px) {
.navbar-expand-xl {
@@ -3782,7 +3783,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.navbar-expand-xl .navbar-toggler {
display:none
}
-
+
}
.navbar-expand {
-ms-flex-flow:row nowrap;
@@ -4010,7 +4011,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
margin-bottom:0;
margin-left:15px
}
-
+
}
.card-group>.card {
margin-bottom:15px
@@ -4051,7 +4052,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom {
border-bottom-left-radius:0
}
-
+
}
.card-columns .card {
margin-bottom:.75rem
@@ -4071,7 +4072,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
display:inline-block;
width:100%
}
-
+
}
.accordion {
overflow-anchor:none
@@ -4218,7 +4219,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.badge {
transition:none
}
-
+
}
a.badge:focus,a.badge:hover {
text-decoration:none
@@ -4341,7 +4342,7 @@ a.badge-dark.focus,a.badge-dark:focus {
.jumbotron {
padding:4rem 2rem
}
-
+
}
.jumbotron-fluid {
padding-right:0;
@@ -4467,7 +4468,7 @@ a.badge-dark.focus,a.badge-dark:focus {
to {
background-position:0 0
}
-
+
}
@keyframes progress-bar-stripes {
from {
@@ -4476,7 +4477,7 @@ a.badge-dark.focus,a.badge-dark:focus {
to {
background-position:0 0
}
-
+
}
.progress {
display:-ms-flexbox;
@@ -4506,7 +4507,7 @@ a.badge-dark.focus,a.badge-dark:focus {
.progress-bar {
transition:none
}
-
+
}
.progress-bar-striped {
background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);
@@ -4521,7 +4522,7 @@ a.badge-dark.focus,a.badge-dark:focus {
-webkit-animation:none;
animation:none
}
-
+
}
.media {
display:-ms-flexbox;
@@ -4637,7 +4638,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px;
border-left-width:1px
}
-
+
}
@media (min-width:768px) {
.list-group-horizontal-md {
@@ -4663,7 +4664,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px;
border-left-width:1px
}
-
+
}
@media (min-width:992px) {
.list-group-horizontal-lg {
@@ -4689,7 +4690,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px;
border-left-width:1px
}
-
+
}
@media (min-width:1200px) {
.list-group-horizontal-xl {
@@ -4715,7 +4716,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px;
border-left-width:1px
}
-
+
}
.list-group-flush {
border-radius:0
@@ -4930,7 +4931,7 @@ a.close.disabled {
.modal.fade .modal-dialog {
transition:none
}
-
+
}
.modal.show .modal-dialog {
-webkit-transform:none;
@@ -5086,19 +5087,19 @@ a.close.disabled {
.modal-sm {
max-width:300px
}
-
+
}
@media (min-width:992px) {
.modal-lg,.modal-xl {
max-width:800px
}
-
+
}
@media (min-width:1200px) {
.modal-xl {
max-width:1140px
}
-
+
}
.tooltip {
position:absolute;
@@ -5365,7 +5366,7 @@ a.close.disabled {
.carousel-item {
transition:none
}
-
+
}
.carousel-item-next,.carousel-item-prev,.carousel-item.active {
display:block
@@ -5397,7 +5398,7 @@ a.close.disabled {
.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right {
transition:none
}
-
+
}
.carousel-control-next,.carousel-control-prev {
position:absolute;
@@ -5420,7 +5421,7 @@ a.close.disabled {
.carousel-control-next,.carousel-control-prev {
transition:none
}
-
+
}
.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover {
color:#fff;
@@ -5482,7 +5483,7 @@ a.close.disabled {
.carousel-indicators li {
transition:none
}
-
+
}
.carousel-indicators .active {
opacity:1
@@ -5503,14 +5504,14 @@ a.close.disabled {
-webkit-transform:rotate(360deg);
transform:rotate(360deg)
}
-
+
}
@keyframes spinner-border {
to {
-webkit-transform:rotate(360deg);
transform:rotate(360deg)
}
-
+
}
.spinner-border {
display:inline-block;
@@ -5538,7 +5539,7 @@ a.close.disabled {
-webkit-transform:none;
transform:none
}
-
+
}
@keyframes spinner-grow {
0% {
@@ -5550,7 +5551,7 @@ a.close.disabled {
-webkit-transform:none;
transform:none
}
-
+
}
.spinner-grow {
display:inline-block;
@@ -5794,7 +5795,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
display:-ms-inline-flexbox!important;
display:inline-flex!important
}
-
+
}
@media (min-width:768px) {
.d-md-none {
@@ -5826,7 +5827,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
display:-ms-inline-flexbox!important;
display:inline-flex!important
}
-
+
}
@media (min-width:992px) {
.d-lg-none {
@@ -5858,7 +5859,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
display:-ms-inline-flexbox!important;
display:inline-flex!important
}
-
+
}
@media (min-width:1200px) {
.d-xl-none {
@@ -5890,7 +5891,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
display:-ms-inline-flexbox!important;
display:inline-flex!important
}
-
+
}
@media print {
.d-print-none {
@@ -5922,7 +5923,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
display:-ms-inline-flexbox!important;
display:inline-flex!important
}
-
+
}
.embed-responsive {
position:relative;
@@ -6229,7 +6230,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
-ms-flex-item-align:stretch!important;
align-self:stretch!important
}
-
+
}
@media (min-width:768px) {
.flex-md-row {
@@ -6368,7 +6369,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
-ms-flex-item-align:stretch!important;
align-self:stretch!important
}
-
+
}
@media (min-width:992px) {
.flex-lg-row {
@@ -6507,7 +6508,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
-ms-flex-item-align:stretch!important;
align-self:stretch!important
}
-
+
}
@media (min-width:1200px) {
.flex-xl-row {
@@ -6646,7 +6647,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
-ms-flex-item-align:stretch!important;
align-self:stretch!important
}
-
+
}
.float-left {
float:left!important
@@ -6667,7 +6668,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.float-sm-none {
float:none!important
}
-
+
}
@media (min-width:768px) {
.float-md-left {
@@ -6679,7 +6680,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.float-md-none {
float:none!important
}
-
+
}
@media (min-width:992px) {
.float-lg-left {
@@ -6691,7 +6692,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.float-lg-none {
float:none!important
}
-
+
}
@media (min-width:1200px) {
.float-xl-left {
@@ -6703,7 +6704,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.float-xl-none {
float:none!important
}
-
+
}
.user-select-all {
-webkit-user-select:all!important;
@@ -6766,7 +6767,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
top:0;
z-index:1020
}
-
+
}
.sr-only {
position:absolute;
@@ -7388,7 +7389,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.ml-sm-auto,.mx-sm-auto {
margin-left:auto!important
}
-
+
}
@media (min-width:768px) {
.m-md-0 {
@@ -7661,7 +7662,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.ml-md-auto,.mx-md-auto {
margin-left:auto!important
}
-
+
}
@media (min-width:992px) {
.m-lg-0 {
@@ -7934,7 +7935,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.ml-lg-auto,.mx-lg-auto {
margin-left:auto!important
}
-
+
}
@media (min-width:1200px) {
.m-xl-0 {
@@ -8207,7 +8208,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.ml-xl-auto,.mx-xl-auto {
margin-left:auto!important
}
-
+
}
.stretched-link::after {
position:absolute;
@@ -8256,7 +8257,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.text-sm-center {
text-align:center!important
}
-
+
}
@media (min-width:768px) {
.text-md-left {
@@ -8268,7 +8269,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.text-md-center {
text-align:center!important
}
-
+
}
@media (min-width:992px) {
.text-lg-left {
@@ -8280,7 +8281,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.text-lg-center {
text-align:center!important
}
-
+
}
@media (min-width:1200px) {
.text-xl-left {
@@ -8292,7 +8293,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
.text-xl-center {
text-align:center!important
}
-
+
}
.text-lowercase {
text-transform:lowercase!important
@@ -8472,7 +8473,7 @@ a.text-dark:focus,a.text-dark:hover {
color:inherit;
border-color:#dee2e6
}
-
+
}
.bg-primary {
background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);
diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
index 1ed6d7b4b6..30026bb48b 100644
--- a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
+++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
@@ -9,8 +9,7 @@
* Copyright 2011-2020 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
-*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;
-700&display=swap);
+*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap);
:root {
--blue:#2a9fd6;
--indigo:#6610f2;
@@ -36,6 +35,7 @@
--dark:#adafae;
--body-bg: #060606;
--text-bg-mark: #fcf8e3;
+ --custom-select: #fff;
--breakpoint-xs:0;
--breakpoint-sm:576px;
--breakpoint-md:768px;
diff --git a/apps/remix-ide/src/lib/offsetToLineColumnConverter.js b/apps/remix-ide/src/lib/offsetToLineColumnConverter.js
deleted file mode 100644
index b2a2e37e32..0000000000
--- a/apps/remix-ide/src/lib/offsetToLineColumnConverter.js
+++ /dev/null
@@ -1,75 +0,0 @@
-'use strict'
-import { Plugin } from '@remixproject/engine'
-import * as packageJson from '../../../../package.json'
-import { sourceMappingDecoder } from '@remix-project/remix-debug'
-
-const profile = {
- name: 'offsetToLineColumnConverter',
- methods: ['offsetToLineColumn'],
- events: [],
- version: packageJson.version
-}
-
-export class OffsetToLineColumnConverter extends Plugin {
- constructor () {
- super(profile)
- this.lineBreakPositionsByContent = {}
- this.sourceMappingDecoder = sourceMappingDecoder
- }
-
- /**
- * Convert offset representation with line/column representation.
- * This is also used to resolve the content:
- * @arg file is the index of the file in the content sources array and content sources array does have filename as key and not index.
- * So we use the asts (which references both index and filename) to look up the actual content targeted by the @arg file index.
- * @param {{start, length}} rawLocation - offset location
- * @param {number} file - The index where to find the source in the sources parameters
- * @param {Object.} sources - Map of content sources
- * @param {Object.} asts - Map of content sources
- */
- offsetToLineColumn (rawLocation, file, sources, asts) {
- if (!this.lineBreakPositionsByContent[file]) {
- const sourcesArray = Object.keys(sources)
- if (!asts || (file === 0 && sourcesArray.length === 1)) {
- // if we don't have ast, we process the only one available content (applicable also for compiler older than 0.4.12)
- this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[0]].content)
- } else {
- for (var filename in asts) {
- const source = asts[filename]
- if (source.id === file) {
- this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content)
- break
- }
- }
- }
- }
- return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
- }
-
- /**
- * Convert offset representation with line/column representation.
- * @param {{start, length}} rawLocation - offset location
- * @param {number} file - The index where to find the source in the sources parameters
- * @param {string} content - source
- */
- offsetToLineColumnWithContent (rawLocation, file, content) {
- this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(content)
- return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
- }
-
- /**
- * Clear the cache
- */
- clear () {
- this.lineBreakPositionsByContent = {}
- }
-
- /**
- * called by plugin API
- */
- activate () {
- this.on('solidity', 'compilationFinished', () => {
- this.clear()
- })
- }
-}
diff --git a/apps/solidity-compiler/src/app/compiler-api.ts b/apps/solidity-compiler/src/app/compiler-api.ts
index 74eec1d57f..f7eb97442c 100644
--- a/apps/solidity-compiler/src/app/compiler-api.ts
+++ b/apps/solidity-compiler/src/app/compiler-api.ts
@@ -222,10 +222,10 @@ export const CompilerApiMixin = (Base) => class extends Base {
}
this.compiler.event.register('loadingCompiler', this.data.eventHandlers.onLoadingCompiler)
- this.data.eventHandlers.onCompilerLoaded = (version) => {
+ this.data.eventHandlers.onCompilerLoaded = (version, license) => {
this.data.loading = false
this.statusChanged({ key: 'none' })
- this.emit('compilerLoaded', version)
+ this.emit('compilerLoaded', version, license)
}
this.compiler.event.register('compilerLoaded', this.data.eventHandlers.onCompilerLoaded)
diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx
index a6ce7c9db9..18b0fd0a80 100644
--- a/apps/vyper/src/app/app.tsx
+++ b/apps/vyper/src/app/app.tsx
@@ -38,12 +38,15 @@ const App: React.FC = () => {
async function start() {
try {
await remixClient.loaded()
- remixClient.onFileChange(name => setContract(name))
- const name = await remixClient.getContractName()
- setContract(name)
+ remixClient.onFileChange(name => setContract(name))
+ remixClient.onNoFileSelected(() => setContract(''))
} catch (err) {
console.log(err)
}
+ try {
+ const name = await remixClient.getContractName() // throw if no file are selected
+ setContract(name)
+ } catch (e) {}
}
start()
}, [])
diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx
index fb0fb6ff05..c7fe318f0d 100644
--- a/apps/vyper/src/app/components/CompilerButton.tsx
+++ b/apps/vyper/src/app/components/CompilerButton.tsx
@@ -28,22 +28,60 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) {
/** Compile a Contract */
async function compileContract() {
try {
- const _contract = await remixClient.getContract()
+ await remixClient.discardHighlight()
+ let _contract: any
+ try {
+ _contract = await remixClient.getContract()
+ } catch (e: any) {
+ setOutput('', { status: 'failed', message: e.message})
+ return
+ }
remixClient.changeStatus({
key: 'loading',
type: 'info',
title: 'Compiling'
})
- const output = await compile(compilerUrl, _contract)
+ let output
+ try {
+ output = await compile(compilerUrl, _contract)
+ } catch (e: any) {
+ setOutput(_contract.name, { status: 'failed', message: e.message})
+ return
+ }
setOutput(_contract.name, output)
// ERROR
if (isCompilationError(output)) {
const line = output.line
- const lineColumnPos = {
- start: { line: line - 1 },
- end: { line: line - 1 }
+ if (line) {
+ const lineColumnPos = {
+ start: { line: line - 1, column: 10 },
+ end: { line: line - 1, column: 10 }
+ }
+ remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
+ } else {
+ const regex = output.message.match(/line ((\d+):(\d+))+/g)
+ const errors = output.message.split(/line ((\d+):(\d+))+/g) // extract error message
+ if (regex) {
+ let errorIndex = 0
+ regex.map((errorLocation) => {
+ const location = errorLocation.replace('line ', '').split(':')
+ let message = errors[errorIndex]
+ errorIndex = errorIndex + 4
+ if (message && message.split('\n\n').length > 0) {
+ try {
+ message = message.split('\n\n')[1]
+ } catch (e) {}
+ }
+ if (location.length > 0) {
+ const lineColumnPos = {
+ start: { line: parseInt(location[0]) - 1, column: 10 },
+ end: { line: parseInt(location[0]) - 1, column: 10 }
+ }
+ remixClient.highlight(lineColumnPos as any, _contract.name, message)
+ }
+ })
+ }
}
- remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
throw new Error(output.message)
}
// SUCCESS
@@ -61,7 +99,6 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) {
type: 'error',
title: err.message
})
- console.error(err)
}
}
diff --git a/apps/vyper/src/app/components/LocalUrl.tsx b/apps/vyper/src/app/components/LocalUrl.tsx
index 3659b4094e..5e2dcbacf1 100644
--- a/apps/vyper/src/app/components/LocalUrl.tsx
+++ b/apps/vyper/src/app/components/LocalUrl.tsx
@@ -26,11 +26,10 @@ function LocalUrlInput({ url, setUrl, environment }: Props) {
type="email"
placeholder="eg http://localhost:8000/compile" />
- The url to your local compiler
)
}
-export default LocalUrlInput;
\ No newline at end of file
+export default LocalUrlInput;
diff --git a/apps/vyper/src/app/components/VyperResult.tsx b/apps/vyper/src/app/components/VyperResult.tsx
index f550d17370..e58f901fea 100644
--- a/apps/vyper/src/app/components/VyperResult.tsx
+++ b/apps/vyper/src/app/components/VyperResult.tsx
@@ -7,7 +7,6 @@ import {
} from '../utils';
import Tabs from 'react-bootstrap/Tabs'
import Tab from 'react-bootstrap/Tab'
-import { Ballot } from '../examples/ballot';
import Button from 'react-bootstrap/Button';
import JSONTree from 'react-json-view'
import { CopyToClipboard } from '@remix-ui/clipboard'
@@ -17,14 +16,20 @@ interface VyperResultProps {
output?: VyperCompilationOutput;
}
+export type ExampleContract = {
+ name: string,
+ address: string
+}
+
function VyperResult({ output }: VyperResultProps) {
- const [ active, setActive ] = useState('abi');
-
+ const [ active, setActive ] = useState('abi')
+
if (!output) return (
+
No contract compiled yet.
-
)
@@ -33,7 +38,7 @@ function VyperResult({ output }: VyperResultProps) {
return (
-
{output.message}
+
{output.message}
)
}
@@ -41,7 +46,7 @@ function VyperResult({ output }: VyperResultProps) {
setActive(key)}>
JSON.stringify(output.abi)}>
- Copy ABI
+ Copy ABI
diff --git a/apps/vyper/src/app/examples/ballot.tsx b/apps/vyper/src/app/examples/ballot.tsx
deleted file mode 100644
index 4b368c6fda..0000000000
--- a/apps/vyper/src/app/examples/ballot.tsx
+++ /dev/null
@@ -1,161 +0,0 @@
-export const Ballot = {
- name: 'browser/ballot.vy',
- content: `# Voting with delegation.
-
- # Information about voters
- struct Voter:
- # weight is accumulated by delegation
- weight: int128
- # if true, that person already voted (which includes voting by delegating)
- voted: bool
- # person delegated to
- delegate: address
- # index of the voted proposal, which is not meaningful unless 'voted' is True.
- vote: int128
-
- # Users can create proposals
- struct Proposal:
- # short name (up to 32 bytes)
- name: bytes32
- # number of accumulated votes
- voteCount: int128
-
- voters: public(map(address, Voter))
- proposals: public(map(int128, Proposal))
- voterCount: public(int128)
- chairperson: public(address)
- int128Proposals: public(int128)
-
-
- @public
- @constant
- def delegated(addr: address) -> bool:
- return self.voters[addr].delegate != ZERO_ADDRESS
-
-
- @public
- @constant
- def directlyVoted(addr: address) -> bool:
- return self.voters[addr].voted and (self.voters[addr].delegate == ZERO_ADDRESS)
-
-
- # Setup global variables
- @public
- def __init__(_proposalNames: bytes32[2]):
- self.chairperson = msg.sender
- self.voterCount = 0
- for i in range(2):
- self.proposals[i] = Proposal({
- name: _proposalNames[i],
- voteCount: 0
- })
- self.int128Proposals += 1
-
- # Give a 'voter' the right to vote on this ballot.
- # This may only be called by the 'chairperson'.
- @public
- def giveRightToVote(voter: address):
- # Throws if the sender is not the chairperson.
- assert msg.sender == self.chairperson
- # Throws if the voter has already voted.
- assert not self.voters[voter].voted
- # Throws if the voter's voting weight isn't 0.
- assert self.voters[voter].weight == 0
- self.voters[voter].weight = 1
- self.voterCount += 1
-
- # Used by 'delegate' below, and can be called by anyone.
- @public
- def forwardWeight(delegate_with_weight_to_forward: address):
- assert self.delegated(delegate_with_weight_to_forward)
- # Throw if there is nothing to do:
- assert self.voters[delegate_with_weight_to_forward].weight > 0
-
- target: address = self.voters[delegate_with_weight_to_forward].delegate
- for i in range(4):
- if self.delegated(target):
- target = self.voters[target].delegate
- # The following effectively detects cycles of length <= 5,
- # in which the delegation is given back to the delegator.
- # This could be done for any int128ber of loops,
- # or even infinitely with a while loop.
- # However, cycles aren't actually problematic for correctness;
- # they just result in spoiled votes.
- # So, in the production version, this should instead be
- # the responsibility of the contract's client, and this
- # check should be removed.
- assert target != delegate_with_weight_to_forward
- else:
- # Weight will be moved to someone who directly voted or
- # hasn't voted.
- break
-
- weight_to_forward: int128 = self.voters[delegate_with_weight_to_forward].weight
- self.voters[delegate_with_weight_to_forward].weight = 0
- self.voters[target].weight += weight_to_forward
-
- if self.directlyVoted(target):
- self.proposals[self.voters[target].vote].voteCount += weight_to_forward
- self.voters[target].weight = 0
-
- # To reiterate: if target is also a delegate, this function will need
- # to be called again, similarly to as above.
-
- # Delegate your vote to the voter 'to'.
- @public
- def delegate(to: address):
- # Throws if the sender has already voted
- assert not self.voters[msg.sender].voted
- # Throws if the sender tries to delegate their vote to themselves or to
- # the default address value of 0x0000000000000000000000000000000000000000
- # (the latter might not be problematic, but I don't want to think about it).
- assert to != msg.sender
- assert to != ZERO_ADDRESS
-
- self.voters[msg.sender].voted = True
- self.voters[msg.sender].delegate = to
-
- # This call will throw if and only if this delegation would cause a loop
- # of length <= 5 that ends up delegating back to the delegator.
- self.forwardWeight(msg.sender)
-
- # Give your vote (including votes delegated to you)
- # to proposal 'proposals[proposal].name'.
- @public
- def vote(proposal: int128):
- # can't vote twice
- assert not self.voters[msg.sender].voted
- # can only vote on legitimate proposals
- assert proposal < self.int128Proposals
-
- self.voters[msg.sender].vote = proposal
- self.voters[msg.sender].voted = True
-
- # transfer msg.sender's weight to proposal
- self.proposals[proposal].voteCount += self.voters[msg.sender].weight
- self.voters[msg.sender].weight = 0
-
- # Computes the winning proposal taking all
- # previous votes into account.
- @public
- @constant
- def winningProposal() -> int128:
- winning_vote_count: int128 = 0
- winning_proposal: int128 = 0
- for i in range(2):
- if self.proposals[i].voteCount > winning_vote_count:
- winning_vote_count = self.proposals[i].voteCount
- winning_proposal = i
- return winning_proposal
-
- # Calls winningProposal() function to get the index
- # of the winner contained in the proposals array and then
- # returns the name of the winner
- @public
- @constant
- def winnerName() -> bytes32:
- return self.proposals[self.winningProposal()].name
-
- `
- }
-
\ No newline at end of file
diff --git a/apps/vyper/src/app/utils/compiler.tsx b/apps/vyper/src/app/utils/compiler.tsx
index ebc117dba1..0b65c65a1a 100644
--- a/apps/vyper/src/app/utils/compiler.tsx
+++ b/apps/vyper/src/app/utils/compiler.tsx
@@ -18,8 +18,8 @@ export interface VyperCompilationResult {
export interface VyperCompilationError {
status: 'failed'
- column: number
- line: number
+ column?: number
+ line?: number
message: string
}
diff --git a/apps/vyper/src/app/utils/remix-client.tsx b/apps/vyper/src/app/utils/remix-client.tsx
index 080ba64a75..913131e594 100644
--- a/apps/vyper/src/app/utils/remix-client.tsx
+++ b/apps/vyper/src/app/utils/remix-client.tsx
@@ -3,6 +3,7 @@ import { Api, Status } from '@remixproject/plugin-utils';
import { createClient } from '@remixproject/plugin-webview'
import { PluginClient } from '@remixproject/plugin';
import { Contract } from './compiler';
+import { ExampleContract } from '../components/VyperResult';
export class RemixClient extends PluginClient {
private client = createClient>(this);
@@ -14,34 +15,70 @@ export class RemixClient extends PluginClient {
/** Emit an event when file changed */
async onFileChange(cb: (contract: string) => any) {
this.client.on('fileManager', 'currentFileChanged', async (name: string) => {
- if (!name) return
cb(name)
})
}
+ /** Emit an event when file changed */
+ async onNoFileSelected(cb: () => any) {
+ this.client.on('fileManager', 'noFileSelected', async () => {
+ cb()
+ })
+ }
+
/** Load Ballot contract example into the file manager */
- async loadContract({name, content}: Contract) {
+ async loadContract({name, address}: ExampleContract) {
try {
- await this.client.call('fileManager', 'setFile', name, content)
- await this.client.call('fileManager', 'switchFile', name)
+ const content = await this.client.call('contentImport', 'resolve', address)
+ await this.client.call('fileManager', 'setFile', content.cleanUrl, content.content)
+ await this.client.call('fileManager', 'switchFile', content.cleanUrl)
} catch (err) {
console.log(err)
}
}
+ async cloneVyperRepo() {
+ try {
+ // @ts-ignore
+ this.call('notification', 'toast', 'cloning Vyper repository...')
+ await this.call('manager', 'activatePlugin', 'dGitProvider')
+ // @ts-ignore
+ await this.call('dGitProvider', 'clone', { url: 'https://github.com/vyperlang/vyper', token: null }, 'vyper-lang')
+ // @ts-ignore
+ this.call('notification', 'toast', 'Vyper repository cloned, the workspace Vyper has been created.')
+ } catch (e) {
+ // @ts-ignore
+ this.call('notification', 'toast', e.message)
+ }
+ }
+
/** Update the status of the plugin in remix */
changeStatus(status: Status) {
this.client.emit('statusChanged', status);
}
/** Highlight a part of the editor */
- highlight(lineColumnPos: HighlightPosition, name: string, color: string) {
- return this.client.call('editor', 'highlight', lineColumnPos, name, color)
+ async highlight(lineColumnPos: HighlightPosition, name: string, message: string) {
+ await this.client.call('editor', 'highlight', lineColumnPos, name)
+ /*
+ column: -1
+ row: -1
+ text: "browser/Untitled1.sol: Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.↵"
+ type: "warning"
+ */
+ const annotation = {
+ column: 0,
+ row: lineColumnPos.start.line,
+ type: 'error',
+ text: message
+ }
+ await this.client.call('editor', 'addAnnotation', annotation, name)
}
/** Remove current Hightlight */
- discardHighlight() {
- return this.client.call('editor', 'discardHighlight')
+ async discardHighlight() {
+ await this.client.call('editor', 'discardHighlight')
+ await this.client.call('editor', 'clearAnnotations')
}
/** Get the name of the current contract */
diff --git a/libs/remix-lib/src/execution/txListener.ts b/libs/remix-lib/src/execution/txListener.ts
index 0d5b26eb84..808d9fe4e0 100644
--- a/libs/remix-lib/src/execution/txListener.ts
+++ b/libs/remix-lib/src/execution/txListener.ts
@@ -1,5 +1,4 @@
'use strict'
-import { each } from 'async'
import { ethers } from 'ethers'
import { toBuffer, addHexPrefix } from 'ethereumjs-util'
import { EventManager } from '../eventManager'
@@ -34,8 +33,7 @@ export class TxListener {
_listenOnNetwork:boolean
_loopId
blocks
- lastBlock
-
+
constructor (opt, executionContext) {
this.event = new EventManager()
// has a default for now for backwards compatability
@@ -107,8 +105,7 @@ export class TxListener {
addExecutionCosts(txResult, tx, execResult)
tx.envMode = this.executionContext.getProvider()
tx.status = txResult.receipt.status // 0x0 or 0x1
- this._resolve([tx], () => {
- })
+ this._resolve([tx])
})
})
}
@@ -123,9 +120,7 @@ export class TxListener {
if (this._loopId) {
clearInterval(this._loopId)
}
- if (this._listenOnNetwork) {
- this._startListenOnNetwork()
- }
+ this._listenOnNetwork ? this.startListening() : this.stopListening()
}
/**
@@ -133,7 +128,6 @@ export class TxListener {
*/
init () {
this.blocks = []
- this.lastBlock = -1
}
/**
@@ -164,34 +158,54 @@ export class TxListener {
this._isListening = false
}
- _startListenOnNetwork () {
- this._loopId = setInterval(() => {
+ async _startListenOnNetwork () {
+ let lastSeenBlock = this.executionContext.lastBlock?.number - 1
+ let processingBlock = false
+
+ const processBlocks = async () => {
+ if (!this._isListening) return
+ if (processingBlock) return
+ processingBlock = true
const currentLoopId = this._loopId
- this.executionContext.web3().eth.getBlockNumber((error, blockNumber) => {
- if (this._loopId === null) return
- if (error) return console.log(error)
- if (currentLoopId === this._loopId && blockNumber > this.lastBlock) {
- let current = this.lastBlock + 1
- this.lastBlock = blockNumber
- while (blockNumber >= current) {
- try {
- this._manageBlock(current)
- } catch (e) {
- console.log(e)
- }
- current++
+ if (this._loopId === null) {
+ processingBlock = false
+ return
+ }
+ if (!lastSeenBlock) {
+ lastSeenBlock = this.executionContext.lastBlock?.number // trying to resynchronize
+ console.log('listen on blocks, resynchronising')
+ processingBlock = false
+ return
+ }
+ const current = this.executionContext.lastBlock?.number
+ if (!current) {
+ console.log(new Error('no last block found'))
+ processingBlock = false
+ return
+ }
+ if (currentLoopId === this._loopId && lastSeenBlock < current) {
+ while (lastSeenBlock <= current) {
+ try {
+ if (!this._isListening) break
+ await this._manageBlock(lastSeenBlock)
+ } catch (e) {
+ console.log(e)
}
+ lastSeenBlock++
}
- })
- }, 2000)
+ lastSeenBlock = current
+ }
+ processingBlock = false
+ }
+ this._loopId = setInterval(processBlocks, 20000)
+ processBlocks()
}
- _manageBlock (blockNumber) {
- this.executionContext.web3().eth.getBlock(blockNumber, true, (error, result) => {
- if (!error) {
- this._newBlock(Object.assign({ type: 'web3' }, result))
- }
- })
+ async _manageBlock (blockNumber) {
+ try {
+ const result = await this.executionContext.web3().eth.getBlock(blockNumber, true)
+ return await this._newBlock(Object.assign({ type: 'web3' }, result))
+ } catch (e) {}
}
/**
@@ -215,31 +229,37 @@ export class TxListener {
return this._resolvedTransactions[txHash]
}
- _newBlock (block) {
+ async _newBlock (block) {
this.blocks.push(block)
- this._resolve(block.transactions, () => {
- this.event.trigger('newBlock', [block])
- })
+ await this._resolve(block.transactions)
+ this.event.trigger('newBlock', [block])
}
- _resolve (transactions, callback) {
- each(transactions, (tx, cb) => {
+ _resolveAsync (tx) {
+ return new Promise((resolve, reject) => {
this._api.resolveReceipt(tx, (error, receipt) => {
- if (error) return cb(error)
+ if (error) return reject(error)
this._resolveTx(tx, receipt, (error, resolvedData) => {
- if (error) cb(error)
+ if (error) return reject(error)
if (resolvedData) {
this.event.trigger('txResolved', [tx, receipt, resolvedData])
}
this.event.trigger('newTransaction', [tx, receipt])
- cb()
+ resolve({})
})
})
- }, () => {
- callback()
})
}
+ async _resolve (transactions) {
+ for (const tx of transactions) {
+ try {
+ if (!this._isListening) break
+ await this._resolveAsync(tx)
+ } catch (e) {}
+ }
+ }
+
_resolveTx (tx, receipt, cb) {
const contracts = this._api.contracts()
if (!contracts) return cb()
diff --git a/libs/remix-lib/src/helpers/hhconsoleSigs.ts b/libs/remix-lib/src/helpers/hhconsoleSigs.ts
index 1ae8955736..ee1c9dbcc0 100644
--- a/libs/remix-lib/src/helpers/hhconsoleSigs.ts
+++ b/libs/remix-lib/src/helpers/hhconsoleSigs.ts
@@ -375,5 +375,7 @@ export const ConsoleLogs = {
3982404743: '(address,address,address,uint)',
4161329696: '(address,address,address,string)',
238520724: '(address,address,address,bool)',
- 1717301556: '(address,address,address,address)'
+ 1717301556: '(address,address,address,address)',
+ 4133908826: '(uint,uint)',
+ 3054400204: '(string,uint)'
}
diff --git a/libs/remix-solidity/src/compiler/compiler-worker.ts b/libs/remix-solidity/src/compiler/compiler-worker.ts
index 662a03ec06..313d1b0119 100644
--- a/libs/remix-solidity/src/compiler/compiler-worker.ts
+++ b/libs/remix-solidity/src/compiler/compiler-worker.ts
@@ -33,7 +33,8 @@ export default function (self) { // eslint-disable-line @typescript-eslint/expli
}
self.postMessage({
cmd: 'versionLoaded',
- data: compiler.version()
+ data: compiler.version(),
+ license: compiler.license()
})
break
}
diff --git a/libs/remix-solidity/src/compiler/compiler.ts b/libs/remix-solidity/src/compiler/compiler.ts
index f728748a9e..20aa8880a2 100644
--- a/libs/remix-solidity/src/compiler/compiler.ts
+++ b/libs/remix-solidity/src/compiler/compiler.ts
@@ -25,6 +25,7 @@ export class Compiler {
compileJSON: null,
worker: null,
currentVersion: null,
+ compilerLicense: null,
optimize: false,
runs: 200,
evmVersion: null,
@@ -94,9 +95,10 @@ export class Compiler {
* @param version compiler version
*/
- onCompilerLoaded (version: string): void {
+ onCompilerLoaded (version: string, license: string): void {
this.state.currentVersion = version
- this.event.trigger('compilerLoaded', [version])
+ this.state.compilerLicense = license
+ this.event.trigger('compilerLoaded', [version, license])
}
/**
@@ -131,7 +133,7 @@ export class Compiler {
}
this.onCompilationFinished(result, missingInputs, source, input, this.state.currentVersion)
}
- this.onCompilerLoaded(compiler.version())
+ this.onCompilerLoaded(compiler.version(), compiler.license())
}
}
@@ -184,6 +186,7 @@ export class Compiler {
if (err) {
console.error('Error in loading remote solc compiler: ', err)
} else {
+ let license
this.state.compileJSON = (source: SourceWithTarget) => {
const missingInputs: string[] = []
const missingInputsCallback = (path: string) => {
@@ -203,13 +206,14 @@ export class Compiler {
}
result = JSON.parse(remoteCompiler.compile(input, { import: missingInputsCallback }))
+ license = remoteCompiler.license()
}
} catch (exception) {
result = { error: { formattedMessage: 'Uncaught JavaScript exception:\n' + exception, severity: 'error', mode: 'panic' } }
}
this.onCompilationFinished(result, missingInputs, source, input, version)
}
- this.onCompilerLoaded(version)
+ this.onCompilerLoaded(version, license)
}
})
}
@@ -273,7 +277,7 @@ export class Compiler {
const data: MessageFromWorker = msg.data
switch (data.cmd) {
case 'versionLoaded':
- if (data.data) this.onCompilerLoaded(data.data)
+ if (data.data && data.license) this.onCompilerLoaded(data.data, data.license)
break
case 'compiled':
{
diff --git a/libs/remix-solidity/src/compiler/types.ts b/libs/remix-solidity/src/compiler/types.ts
index c4e48dd2ff..9f3cfb4b54 100644
--- a/libs/remix-solidity/src/compiler/types.ts
+++ b/libs/remix-solidity/src/compiler/types.ts
@@ -158,6 +158,7 @@ export interface CompilerState {
compileJSON: ((input: SourceWithTarget) => void) | null,
worker: any,
currentVersion: string| null| undefined,
+ compilerLicense: string| null
optimize: boolean,
runs: number
evmVersion: EVMVersion| null,
@@ -186,6 +187,7 @@ export interface MessageToWorker {
export interface MessageFromWorker {
cmd: string,
+ license?: string,
job?: number,
missingInputs?: string[],
input?: any,
diff --git a/libs/remix-tests/src/compiler.ts b/libs/remix-tests/src/compiler.ts
index b399f7376e..7fedf9c830 100644
--- a/libs/remix-tests/src/compiler.ts
+++ b/libs/remix-tests/src/compiler.ts
@@ -134,7 +134,7 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts
if (runs) compiler.set('runs', runs)
if (currentCompilerUrl) {
compiler.loadRemoteVersion(currentCompilerUrl)
- compiler.event.register('compilerLoaded', this, function (version) {
+ compiler.event.register('compilerLoaded', this, function (version, license) {
next()
})
} else {
@@ -198,7 +198,7 @@ export function compileContractSources (sources: SrcIfc, newCompConfig: any, imp
compiler.set('runs', runs)
compiler.loadVersion(usingWorker, currentCompilerUrl)
// @ts-ignore
- compiler.event.register('compilerLoaded', this, (version) => {
+ compiler.event.register('compilerLoaded', this, (version, license) => {
next()
})
} else {
diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css
index 7bb10333dc..636cfa4eea 100644
--- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css
+++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css
@@ -16,4 +16,8 @@
}
.validationError {
overflow-wrap: break-word;
+}
+.debuggerPanels {
+ overflow-y: scroll;
+ height: fit-content;
}
\ No newline at end of file
diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
index bd8008d0e3..74660fdabe 100644
--- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
+++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react' // eslint-disable-line
+import React, { useState, useEffect, useRef } from 'react' // eslint-disable-line
import TxBrowser from './tx-browser/tx-browser' // eslint-disable-line
import StepManager from './step-manager/step-manager' // eslint-disable-line
import VmDebugger from './vm-debugger/vm-debugger' // eslint-disable-line
@@ -36,6 +36,28 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
sourceLocationStatus: ''
})
+ const panelsRef = useRef(null)
+ const debuggerTopRef = useRef(null)
+
+ const handleResize = () => {
+ if (panelsRef.current && debuggerTopRef.current) {
+ panelsRef.current.style.height = (window.innerHeight - debuggerTopRef.current.clientHeight) - debuggerTopRef.current.offsetTop - 7 +'px'
+ }
+ }
+
+ useEffect(() => {
+ handleResize()
+ }, [])
+
+ useEffect(() => {
+ window.addEventListener('resize', handleResize)
+ // TODO: not a good way to wait on the ref doms element to be rendered of course
+ setTimeout(() =>
+ handleResize(), 2000)
+ return () => window.removeEventListener('resize', handleResize)
+ }, [state.debugging, state.isActive])
+
+
useEffect(() => {
return unLoad()
}, [])
@@ -260,34 +282,35 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
})
setTimeout(async() => {
- try {
- await debuggerInstance.debug(blockNumber, txNumber, tx, () => {
- listenToEvents(debuggerInstance, currentReceipt)
+ try {
+ await debuggerInstance.debug(blockNumber, txNumber, tx, () => {
+ listenToEvents(debuggerInstance, currentReceipt)
+ setState(prevState => {
+ return {
+ ...prevState,
+ blockNumber,
+ txNumber,
+ debugging: true,
+ currentReceipt,
+ currentBlock,
+ currentTransaction,
+ debugger: debuggerInstance,
+ toastMessage: `debugging ${txNumber}`,
+ validationError: ''
+ }
+ })
+ })
+ } catch (error) {
+ unLoad()
setState(prevState => {
return {
...prevState,
- blockNumber,
- txNumber,
- debugging: true,
- currentReceipt,
- currentBlock,
- currentTransaction,
- debugger: debuggerInstance,
- toastMessage: `debugging ${txNumber}`,
- validationError: ''
+ validationError: error.message || error
}
})
- })
- } catch (error) {
- unLoad()
- setState(prevState => {
- return {
- ...prevState,
- validationError: error.message || error
- }
- })
- }
- }, 300)
+ }
+ }, 300)
+ handleResize()
}
const debug = (txHash, web3?) => {
@@ -315,17 +338,18 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
traceLength: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.traceLength : null,
registerEvent: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.event.register.bind(state.debugger.step_manager.event) : null
}
+
const vmDebugger = {
registerEvent: state.debugger && state.debugger.vmDebuggerLogic ? state.debugger.vmDebuggerLogic.event.register.bind(state.debugger.vmDebuggerLogic.event) : null,
triggerEvent: state.debugger && state.debugger.vmDebuggerLogic ? state.debugger.vmDebuggerLogic.event.trigger.bind(state.debugger.vmDebuggerLogic.event) : null
}
+
return (
-
+
-
Debugger Configuration
-
+
{
setState(prevState => {
return { ...prevState, opt: { ...prevState.opt, debugWithGeneratedSources: checked } }
@@ -333,7 +357,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
}} type="checkbox" title="Debug with generated sources" />
- { state.isLocalNodeUsed &&
+ { state.isLocalNodeUsed &&
{
setState(prevState => {
return { ...prevState, opt: { ...prevState.opt, debugWithLocalNode: checked } }
@@ -356,9 +380,11 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
}
{ state.debugging &&
}
+
+
{ state.debugging && }
+ { state.debugging && }
- { state.debugging &&
}
)
}
diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx
index 3a58c1d2f4..612757fe36 100644
--- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx
+++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx
@@ -98,7 +98,7 @@ export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent } })
}, [registerEvent])
return (
-
+
diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
index aad442eef4..2f7ba40384 100644
--- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
+++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
@@ -9,6 +9,8 @@ import { IMarkdownString } from 'monaco-editor'
import './remix-ui-editor.css'
import { loadTypes } from './web-types'
+import monaco from '../types/monaco'
+import { MarkerSeverity } from 'monaco-editor'
type cursorPosition = {
startLineNumber: number,
@@ -60,6 +62,22 @@ export type lineText = {
hoverMessage: IMarkdownString | IMarkdownString[]
}
+type errorMarker = {
+ message: string
+ severity: MarkerSeverity
+ position: {
+ start: {
+ line: number
+ column: number
+ },
+ end: {
+ line: number
+ column: number
+ }
+ },
+ file: string
+}
+
loader.config({ paths: { vs: 'assets/js/monaco-editor/dev/vs' } })
export type DecorationsReturn = {
@@ -91,6 +109,8 @@ export interface EditorUIProps {
addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn
clearDecorationsByPlugin: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
keepDecorationsFor: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
+ addErrorMarker: (errors: []) => void
+ clearErrorMarkers: (sources: string[] | {[fileName: string]: any}) => void
}
}
@@ -120,7 +140,7 @@ export const EditorUI = (props: EditorUIProps) => {
const currentFileRef = useRef('')
// const currentDecorations = useRef({ sourceAnnotationsPerFile: {}, markerPerFile: {} }) // decorations that are currently in use by the editor
// const registeredDecorations = useRef({}) // registered decorations
-
+
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
const formatColor = (name) => {
@@ -278,7 +298,7 @@ export const EditorUI = (props: EditorUIProps) => {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-cairo')
} else if (file.language === 'zokrates') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-zokrates')
- }
+ }
}, [props.currentFile])
const convertToMonacoDecoration = (decoration: lineText | sourceAnnotation | sourceMarker, typeOfDecoration: string) => {
@@ -347,7 +367,7 @@ export const EditorUI = (props: EditorUIProps) => {
registeredDecorations: newRegisteredDecorations
}
}
-
+
props.editorAPI.keepDecorationsFor = (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => {
const model = editorModelsState[filePath]?.model
if (!model) return {
@@ -376,11 +396,62 @@ export const EditorUI = (props: EditorUIProps) => {
registeredDecorations: [{ value: decoration, type: typeOfDecoration }]
}
}
-
+
props.editorAPI.addDecoration = (marker: sourceMarker, filePath: string, typeOfDecoration: string) => {
return addDecoration(marker, filePath, typeOfDecoration)
}
+ props.editorAPI.addErrorMarker = async (errors: errorMarker[]) => {
+
+ const allMarkersPerfile: Record
> = {}
+
+ for (const error of errors) {
+ let filePath = error.file
+
+ if (!filePath) return
+ const fileFromUrl = await props.plugin.call('fileManager', 'getPathFromUrl', filePath)
+ filePath = fileFromUrl.file
+ const model = editorModelsState[filePath]?.model
+ const errorServerityMap = {
+ 'error': MarkerSeverity.Error,
+ 'warning': MarkerSeverity.Warning,
+ 'info': MarkerSeverity.Info
+ }
+ if (model) {
+ const markerData: monaco.editor.IMarkerData = {
+ severity: errorServerityMap[error.severity],
+ startLineNumber: ((error.position.start && error.position.start.line) || 0),
+ startColumn: ((error.position.start && error.position.start.column) || 0),
+ endLineNumber: ((error.position.end && error.position.end.line) || 0),
+ endColumn: ((error.position.end && error.position.end.column) || 0),
+ message: error.message,
+ }
+ if (!allMarkersPerfile[filePath]) {
+ allMarkersPerfile[filePath] = []
+ }
+ allMarkersPerfile[filePath].push(markerData)
+ }
+ }
+ for (const filePath in allMarkersPerfile) {
+ const model = editorModelsState[filePath]?.model
+ if (model) {
+ monacoRef.current.editor.setModelMarkers(model, 'remix-solidity', allMarkersPerfile[filePath])
+ }
+ }
+ }
+
+ props.editorAPI.clearErrorMarkers = async (sources: string[] | {[fileName: string]: any}) => {
+ if (sources) {
+ for (const source of (Array.isArray(sources) ? sources : Object.keys(sources))) {
+ const filePath = source
+ const model = editorModelsState[filePath]?.model
+ if (model) {
+ monacoRef.current.editor.setModelMarkers(model, 'remix-solidity', [])
+ }
+ }
+ }
+ }
+
props.editorAPI.findMatches = (uri: string, value: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
@@ -435,7 +506,7 @@ export const EditorUI = (props: EditorUIProps) => {
}
}
- function handleEditorDidMount (editor) {
+ function handleEditorDidMount(editor) {
editorRef.current = editor
defineAndSetTheme(monacoRef.current)
reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
@@ -453,7 +524,7 @@ export const EditorUI = (props: EditorUIProps) => {
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.US_MINUS, () => {
editor.updateOptions({ fontSize: editor.getOption(43).fontSize - 1 })
})
-
+
// add context menu items
const zoominAction = {
id: "zoomIn",
@@ -483,25 +554,25 @@ export const EditorUI = (props: EditorUIProps) => {
const editorService = editor._codeEditorService;
const openEditorBase = editorService.openCodeEditor.bind(editorService);
editorService.openCodeEditor = async (input, source) => {
- const result = await openEditorBase(input, source)
- if (input && input.resource && input.resource.path) {
- try {
- await props.plugin.call('fileManager', 'open', input.resource.path)
- } catch (e) {
- console.log(e)
- }
+ const result = await openEditorBase(input, source)
+ if (input && input.resource && input.resource.path) {
+ try {
+ await props.plugin.call('fileManager', 'open', input.resource.path)
+ } catch (e) {
+ console.log(e)
}
- return result
+ }
+ return result
}
}
- function handleEditorWillMount (monaco) {
+ function handleEditorWillMount(monaco) {
monacoRef.current = monaco
// Register a new language
monacoRef.current.languages.register({ id: 'remix-solidity' })
monacoRef.current.languages.register({ id: 'remix-cairo' })
monacoRef.current.languages.register({ id: 'remix-zokrates' })
-
+
// Register a tokens provider for the language
monacoRef.current.languages.setMonarchTokensProvider('remix-solidity', solidityTokensProvider)
monacoRef.current.languages.setLanguageConfiguration('remix-solidity', solidityLanguageConfig)
@@ -523,7 +594,7 @@ export const EditorUI = (props: EditorUIProps) => {
language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'}
onMount={handleEditorDidMount}
beforeMount={handleEditorWillMount}
- options={{ glyphMargin: true, readOnly: true}}
+ options={{ glyphMargin: true, readOnly: true }}
defaultValue={defaultEditorValue}
/>
@@ -531,9 +602,9 @@ export const EditorUI = (props: EditorUIProps) => {
hide={false}
gotoLine={(line, column) => props.plugin.call('editor', 'gotoLine', line, column)}
openFile={(file) => props.plugin.call('fileManager', 'switchFile', file)}
- getLastCompilationResult={() => { return props.plugin.call('compilerArtefacts', 'getLastCompilationResult') } }
- offsetToLineColumn={(position, file, sources, asts) => { return props.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn', position, file, sources, asts) } }
- getCurrentFileName={() => { return props.plugin.call('fileManager', 'file') } }
+ getLastCompilationResult={() => { return props.plugin.call('compilerArtefacts', 'getLastCompilationResult') }}
+ offsetToLineColumn={(position, file, sources, asts) => { return props.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn', position, file, sources, asts) }}
+ getCurrentFileName={() => { return props.plugin.call('fileManager', 'file') }}
onContextListenerChanged={(listener) => { props.plugin.on('contextualListener', 'contextChanged', listener) }}
onCurrentFileChanged={(listener) => { props.plugin.on('fileManager', 'currentFileChanged', listener) }}
referencesOf={(node: astNode) => { return props.plugin.call('contextualListener', 'referencesOf', node) }}
diff --git a/libs/remix-ui/helper/src/index.ts b/libs/remix-ui/helper/src/index.ts
index 9f050ea8b8..19e7721ac3 100644
--- a/libs/remix-ui/helper/src/index.ts
+++ b/libs/remix-ui/helper/src/index.ts
@@ -1,4 +1,5 @@
export * from './lib/remix-ui-helper'
+export * from './lib/bleach'
export * from './lib/helper-components'
export * from './lib/components/PluginViewWrapper'
export * from './lib/components/custom-dropdown'
\ No newline at end of file
diff --git a/apps/remix-ide/src/lib/remixBleach.js b/libs/remix-ui/helper/src/lib/bleach.ts
similarity index 87%
rename from apps/remix-ide/src/lib/remixBleach.js
rename to libs/remix-ui/helper/src/lib/bleach.ts
index e159c8a6df..44aa129042 100644
--- a/apps/remix-ide/src/lib/remixBleach.js
+++ b/libs/remix-ui/helper/src/lib/bleach.ts
@@ -5,7 +5,7 @@
*/
import * as he from 'he'
-const remixBleach = {
+export const bleach = {
matcher: /<\/?([a-zA-Z0-9]+)*(.*?)\/?>/igm,
@@ -24,7 +24,7 @@ const remixBleach = {
let match
// extract all tags
- while ((match = remixBleach.matcher.exec(html)) != null) {
+ while ((match = bleach.matcher.exec(html)) != null) {
const attrr = match[2].split(' ')
const attrs = []
@@ -45,7 +45,7 @@ const remixBleach = {
if (attr.name) attrs.push(attr)
})
- var tag = {
+ const tag = {
full: match[0],
name: match[1],
attr: attrs
@@ -57,14 +57,13 @@ const remixBleach = {
return matches
},
- sanitize: function (html, options) {
+ sanitize: function (html, options = { mode: 'white', list: bleach.whitelist, encode_entities: false}) {
html = String(html) || ''
- options = options || {}
-
+
const mode = options.mode || 'white'
- const list = options.list || remixBleach.whitelist
+ const list = options.list || bleach.whitelist
- var matches = remixBleach.analyze(html)
+ const matches = bleach.analyze(html)
if ((mode === 'white' && list.indexOf('script') === -1) ||
(mode === 'black' && list.indexOf('script') !== -1)) {
@@ -95,5 +94,3 @@ const remixBleach = {
return html
}
}
-
-module.exports = remixBleach
diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css
index 6f6cd9b221..62a0dd5987 100644
--- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css
+++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css
@@ -8,6 +8,7 @@
.remixModalBody {
overflow-y: auto;
max-height: 600px;
+ white-space: pre-line;
}
@-webkit-keyframes animatetop {
from {top: -300px; opacity: 0}
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
index 4bffb2565f..b6e8c9948a 100644
--- a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
+++ b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
@@ -27,8 +27,8 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
return (
-
{plugin?.profile.displayName || plugin?.profile.name}
-
+
{plugin?.profile.displayName || plugin?.profile.name}
+
{plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && ()}
diff --git a/libs/remix-ui/run-tab/src/lib/actions/actions.ts b/libs/remix-ui/run-tab/src/lib/actions/actions.ts
index a99a8b3800..669851a869 100644
--- a/libs/remix-ui/run-tab/src/lib/actions/actions.ts
+++ b/libs/remix-ui/run-tab/src/lib/actions/actions.ts
@@ -1,5 +1,5 @@
import { ContractData } from "@remix-project/core-plugin"
-import { addNewInstance, addProvider, clearAllInstances, clearRecorderCount, hidePopUp, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue, setTxFeeContent } from "./payload"
+import { addNewInstance, addProvider, clearAllInstances, clearRecorderCount, hidePopUp, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue } from "./payload"
export const setAccount = (dispatch: React.Dispatch
, account: string) => {
dispatch(setSelectedAccount(account))
@@ -65,10 +65,6 @@ export const updateGasPrice = (dispatch: React.Dispatch, price: string) =>
dispatch(setGasPrice(price))
}
-export const updateTxFeeContent = (dispatch: React.Dispatch, content: string) => {
- dispatch(setTxFeeContent(content))
-}
-
export const addInstance = (dispatch: React.Dispatch, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record }) => {
instance.decodedResponse = {}
dispatch(addNewInstance(instance))
diff --git a/libs/remix-ui/run-tab/src/lib/actions/index.ts b/libs/remix-ui/run-tab/src/lib/actions/index.ts
index 6a20e9470d..f61de6ebd8 100644
--- a/libs/remix-ui/run-tab/src/lib/actions/index.ts
+++ b/libs/remix-ui/run-tab/src/lib/actions/index.ts
@@ -5,7 +5,7 @@ import { resetAndInit, setupEvents } from './events'
import { createNewBlockchainAccount, fillAccountsList, setExecutionContext, signMessageWithAddress } from './account'
import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt,
setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit,
- updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath, updateTxFeeContent } from './actions'
+ updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath } from './actions'
import { createInstance, getContext, getFuncABIInputs, getSelectedContract, loadAddress, runTransactions, updateInstanceBalance } from './deploy'
import { CompilerAbstract as CompilerAbstractType } from '@remix-project/remix-solidity-ts'
import { ContractData, FuncABI } from "@remix-project/core-plugin"
@@ -50,7 +50,6 @@ export const setGasPrice = (price: string) => updateGasPrice(dispatch, price)
export const setGasPriceStatus = (status: boolean) => updateGasPriceStatus(dispatch, status)
export const setMaxFee = (fee: string) => updateMaxFee(dispatch, fee)
export const setMaxPriorityFee = (fee: string) => updateMaxPriorityFee(dispatch, fee)
-export const setTxFeeContent = (content: string) => updateTxFeeContent(dispatch, content)
export const removeInstances = () => clearInstances(dispatch)
export const removeSingleInstance = (index: number) => removeInstance(dispatch, index)
export const getExecutionContext = () => getContext(plugin)
diff --git a/libs/remix-ui/run-tab/src/lib/actions/payload.ts b/libs/remix-ui/run-tab/src/lib/actions/payload.ts
index bb0fc91a41..fac454ca0b 100644
--- a/libs/remix-ui/run-tab/src/lib/actions/payload.ts
+++ b/libs/remix-ui/run-tab/src/lib/actions/payload.ts
@@ -1,6 +1,6 @@
import { ContractList } from '../reducers/runTab'
import { ContractData } from '@remix-project/core-plugin'
-import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_PROXY_ENV_ADDRESS, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_TX_FEE_CONTENT } from '../constants'
+import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_PROXY_ENV_ADDRESS, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE } from '../constants'
import { DeployMode, DeployOptions } from '../types'
export const fetchAccountsListRequest = () => {
@@ -216,13 +216,6 @@ export const setGasPrice = (price: string) => {
}
}
-export const setTxFeeContent = (content: string) => {
- return {
- type: SET_TX_FEE_CONTENT,
- payload: content
- }
-}
-
export const addNewInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any }) => {
return {
type: ADD_INSTANCE,
diff --git a/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx b/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
index a224c94242..c3b08c0858 100644
--- a/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
+++ b/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
@@ -28,6 +28,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const [constructorInterface, setConstructorInterface] = useState(null)
const [constructorInputs, setConstructorInputs] = useState(null)
const contractsRef = useRef(null)
+ const atAddressValue = useRef(null)
const { contractList, loadType, currentFile, currentContract, compilationCount, deployOptions, proxyKey } = props.contracts
useEffect(() => {
@@ -52,7 +53,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
}, [loadedAddress])
useEffect(() => {
- if (/.(.abi)$/.exec(currentFile)) {
+ if (/.(.abi)$/.exec(currentFile) && "" !== atAddressValue.current.value) {
setAbiLabel({
display: 'block',
content: currentFile
@@ -175,7 +176,6 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const atAddressChanged = (event) => {
const value = event.target.value
-
if (!value) {
enableAtAddress(false)
} else {
@@ -282,6 +282,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
At Address
('')
+ const [transactionFee, setTransactionFee] = useState('')
useEffect(() => {
props.init((txFeeText, gasPriceValue, gasPriceStatus) => {
- if (txFeeText) props.setTxFeeContent(txFeeText)
+ if (txFeeText) setTransactionFee(txFeeText)
if (gasPriceValue) onGasPriceChange(gasPriceValue)
if (props.network && props.network.lastBlock && props.network.lastBlock.baseFeePerGas) {
- const baseFee = Web3.utils.fromWei(Web3.utils.toBN(parseInt(props.network.lastBlock.baseFeePerGas, 16)), 'Gwei')
+ const baseFee = Web3.utils.fromWei(Web3.utils.toBN(props.network.lastBlock.baseFeePerGas), 'Gwei')
setBaseFee(baseFee)
onMaxFeeChange(baseFee)
@@ -24,8 +25,8 @@ export function MainnetPrompt (props: MainnetProps) {
const onMaxFeeChange = (value: string) => {
const maxFee = value
// @ts-ignore
- if (parseInt(props.network.lastBlock.baseFeePerGas, 16) > Web3.utils.toWei(maxFee, 'Gwei')) {
- props.setTxFeeContent('Transaction is invalid. Max fee should not be less than Base fee')
+ if (Web3.utils.toBN(props.network.lastBlock.baseFeePerGas).gt(Web3.utils.toBN(Web3.utils.toWei(maxFee, 'Gwei')))) {
+ setTransactionFee('Transaction is invalid. Max fee should not be less than Base fee')
props.updateGasPriceStatus(false)
props.updateConfirmSettings(true)
return
@@ -35,7 +36,7 @@ export function MainnetPrompt (props: MainnetProps) {
}
props.setNewGasPrice(maxFee, (txFeeText, priceStatus) => {
- props.setTxFeeContent(txFeeText)
+ setTransactionFee(txFeeText)
if (priceStatus) {
props.updateConfirmSettings(false)
} else {
@@ -51,7 +52,7 @@ export function MainnetPrompt (props: MainnetProps) {
const gasPrice = value
props.setNewGasPrice(gasPrice, (txFeeText, priceStatus) => {
- props.setTxFeeContent(txFeeText)
+ setTransactionFee(txFeeText)
props.updateGasPriceStatus(priceStatus)
props.updateGasPrice(gasPrice)
})
@@ -105,7 +106,7 @@ export function MainnetPrompt (props: MainnetProps) {
-
Max fee (Not less than base fee {Web3.utils.fromWei(Web3.utils.toBN(parseInt(props.network.lastBlock.baseFeePerGas, 16)), 'Gwei')} Gwei):
+
Max fee (Not less than base fee {Web3.utils.fromWei(Web3.utils.toBN(props.network.lastBlock.baseFeePerGas), 'Gwei')} Gwei):
onMaxFeeChange(e.target.value)} defaultValue={baseFee} />
Gwei
@@ -120,7 +121,7 @@ export function MainnetPrompt (props: MainnetProps) {
}
Max transaction fee:
- { props.txFeeContent }
+ { transactionFee }
diff --git a/libs/remix-ui/run-tab/src/lib/constants/index.ts b/libs/remix-ui/run-tab/src/lib/constants/index.ts
index 91dd777b3b..646cc4a14f 100644
--- a/libs/remix-ui/run-tab/src/lib/constants/index.ts
+++ b/libs/remix-ui/run-tab/src/lib/constants/index.ts
@@ -32,7 +32,6 @@ export const SET_MAX_FEE = 'SET_MAX_FEE'
export const SET_MAX_PRIORITY_FEE = 'SET_MAX_PRIORITY_FEE'
export const SET_BASE_FEE_PER_GAS = 'SET_BASE_FEE_PER_GAS'
export const SET_GAS_PRICE = 'SET_GAS_PRICE'
-export const SET_TX_FEE_CONTENT = 'SET_TX_FEE_CONTENT'
export const ADD_INSTANCE = 'ADD_INSTANCE'
export const REMOVE_INSTANCE = 'REMOVE_INSTANCE'
export const CLEAR_INSTANCES = 'CLEAR_INSTANCES'
diff --git a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
index 5bae13a09e..361a4bf100 100644
--- a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
+++ b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
@@ -1,7 +1,7 @@
import { CompilerAbstract } from '@remix-project/remix-solidity-ts'
import { ContractData } from '@remix-project/core-plugin'
import { DeployOptions } from '../types'
-import { ADD_INSTANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, FETCH_PROVIDER_LIST_FAILED, FETCH_PROVIDER_LIST_REQUEST, FETCH_PROVIDER_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_TX_FEE_CONTENT, SET_PROXY_ENV_ADDRESS, ADD_DEPLOY_OPTION, REMOVE_DEPLOY_OPTION } from '../constants'
+import { ADD_INSTANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, FETCH_PROVIDER_LIST_FAILED, FETCH_PROVIDER_LIST_REQUEST, FETCH_PROVIDER_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_PROXY_ENV_ADDRESS, ADD_DEPLOY_OPTION, REMOVE_DEPLOY_OPTION } from '../constants'
declare const window: any
interface Action {
@@ -82,7 +82,6 @@ export interface RunTabState {
maxFee: string,
maxPriorityFee: string,
baseFeePerGas: string,
- txFeeContent: string,
gasPrice: string,
instances: {
instanceList: {
@@ -171,7 +170,6 @@ export const runTabInitialState: RunTabState = {
maxFee: '',
maxPriorityFee: '1',
baseFeePerGas: '',
- txFeeContent: '',
gasPrice: '',
instances: {
instanceList: [],
@@ -582,15 +580,6 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
}
}
- case SET_TX_FEE_CONTENT: {
- const payload: string = action.payload
-
- return {
- ...state,
- txFeeContent: payload
- }
- }
-
case ADD_INSTANCE: {
const payload: { contractData: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record
} = action.payload
diff --git a/libs/remix-ui/run-tab/src/lib/run-tab.tsx b/libs/remix-ui/run-tab/src/lib/run-tab.tsx
index 128d315201..1ad855434c 100644
--- a/libs/remix-ui/run-tab/src/lib/run-tab.tsx
+++ b/libs/remix-ui/run-tab/src/lib/run-tab.tsx
@@ -21,7 +21,7 @@ import {
setBaseFeePerGas, setConfirmSettings,
setGasPrice, setGasPriceStatus,
setMaxFee, setMaxPriorityFee,
- setTxFeeContent, removeInstances,
+ removeInstances,
removeSingleInstance, getExecutionContext,
executeTransactions, loadFromAddress,
storeNewScenario, runScenario,
@@ -189,8 +189,6 @@ export function RunTabUI (props: RunTabProps) {
updateGasPriceStatus={setGasPriceStatus}
updateMaxFee={setMaxFee}
updateMaxPriorityFee={setMaxPriorityFee}
- setTxFeeContent={setTxFeeContent}
- txFeeContent={runTab.txFeeContent}
maxFee={runTab.maxFee}
maxPriorityFee={runTab.maxPriorityFee}
/>
diff --git a/libs/remix-ui/run-tab/src/lib/types/index.ts b/libs/remix-ui/run-tab/src/lib/types/index.ts
index 8ef73156df..4d1e37524a 100644
--- a/libs/remix-ui/run-tab/src/lib/types/index.ts
+++ b/libs/remix-ui/run-tab/src/lib/types/index.ts
@@ -270,10 +270,8 @@ export interface MainnetProps {
updateMaxFee: (fee: string) => void,
updateBaseFeePerGas: (fee: string) => void,
init: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void,
- setTxFeeContent: (content: string) => void,
updateGasPrice: (price: string) => void,
updateMaxPriorityFee: (fee: string) => void
- txFeeContent: string,
maxFee: string,
maxPriorityFee: string
}
diff --git a/libs/remix-ui/settings/src/lib/github-settings.tsx b/libs/remix-ui/settings/src/lib/github-settings.tsx
index 243598d6ec..6136dd8f95 100644
--- a/libs/remix-ui/settings/src/lib/github-settings.tsx
+++ b/libs/remix-ui/settings/src/lib/github-settings.tsx
@@ -9,9 +9,9 @@ export function GithubSettings (props: GithubSettingsProps) {
useEffect(() => {
if (props.config) {
- const githubToken = props.config.get('settings/gist-access-token')
- const githubUserName = props.config.get('settings/github-user-name')
- const githubEmail = props.config.get('settings/github-email')
+ const githubToken = props.config.get('settings/gist-access-token') || ''
+ const githubUserName = props.config.get('settings/github-user-name') || ''
+ const githubEmail = props.config.get('settings/github-email') || ''
setGithubToken(githubToken)
setGithubUsername(githubUserName)
diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx
index 912da468f3..1d767c7643 100644
--- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx
+++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx
@@ -214,7 +214,7 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
{ labels[type].link }
-
handleSaveTokenState(e, type)} value={ tokenValue[type] } />
+
handleSaveTokenState(e, type)} value={ tokenValue[type] || '' } />
saveToken(type)} value="Save" type="button" disabled={tokenValue === ''}>
diff --git a/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts b/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts
index c67aee6ddb..b1c0b686de 100644
--- a/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts
+++ b/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts
@@ -46,8 +46,8 @@ export const listenToEvents = (compileTabLogic: CompileTabLogic, api) => (dispat
dispatch(setCompilerMode('loadingCompiler'))
})
- compileTabLogic.compiler.event.register('compilerLoaded', () => {
- dispatch(setCompilerMode('compilerLoaded'))
+ compileTabLogic.compiler.event.register('compilerLoaded', (version, license) => {
+ dispatch(setCompilerMode('compilerLoaded', version, license))
})
compileTabLogic.compiler.event.register('compilationFinished', (success, data, source, input, version) => {
diff --git a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
index 069377d045..857a86e73c 100644
--- a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
+++ b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
@@ -48,6 +48,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
timeout: 300,
allversions: [],
customVersions: [],
+ compilerLicense: null,
selectedVersion: null,
defaultVersion: 'soljson-v0.8.7+commit.e28d00a7.js', // this default version is defined: in makeMockCompiler (for browser test)
runs: '',
@@ -185,7 +186,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
loadingCompiler()
break
case 'compilerLoaded':
- compilerLoaded()
+ compilerLoaded(compilerContainer.compiler.args[1])
break
case 'compilationFinished':
compilationFinished()
@@ -432,14 +433,20 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
if (!compileIcon.current) return
compileIcon.current.setAttribute('title', 'compiler is loading, please wait a few moments.')
compileIcon.current.classList.add('remixui_spinningIcon')
+ setState(prevState => {
+ return { ...prevState, compilerLicense: 'Compiler is loading. License will be displayed once compiler is loaded'}
+ })
_updateLanguageSelector()
setDisableCompileButton(true)
}
- const compilerLoaded = () => {
+ const compilerLoaded = (license) => {
if (!compileIcon.current) return
compileIcon.current.setAttribute('title', '')
compileIcon.current.classList.remove('remixui_spinningIcon')
+ setState(prevState => {
+ return { ...prevState, compilerLicense: license ? license : 'Could not retreive license for selected compiler version' }
+ })
if (state.autoCompile) compile()
const isDisabled = !compiledFileName || (compiledFileName && !isSolFileSelected(compiledFileName))
@@ -554,6 +561,10 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
modal('Add a custom compiler', promptMessage('URL'), 'OK', addCustomCompiler, 'Cancel', () => {})
}
+ const showCompilerLicense = () => {
+ modal('Compiler License', state.compilerLicense ? state.compilerLicense : 'License not available', 'OK', () => {})
+ }
+
const promptMessage = (message) => {
return (
<>
@@ -701,10 +712,9 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
-
+
+
promptCompiler()} title="Add a custom compiler with URL">
+
showCompilerLicense()} title="See compiler license">