Merge branch 'master' into intl

pull/2581/head
drafish 3 years ago
commit d0573a149c
  1. 4
      apps/remix-ide-e2e/src/commands/testConstantFunction.ts
  2. 287
      apps/remix-ide-e2e/src/tests/proxy.test.ts
  3. 80
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  4. 2
      apps/remix-ide/src/app/tabs/compile-tab.js
  5. 14
      apps/remix-ide/src/app/tabs/foundry-provider.tsx
  6. 10
      apps/remix-ide/src/app/tabs/ganache-provider.tsx
  7. 6
      apps/remix-ide/src/app/tabs/hardhat-provider.tsx
  8. 1
      apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css
  9. 1
      apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css
  10. 3
      apps/remix-ide/src/assets/css/themes/remix-black_undtds.css
  11. 3
      apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css
  12. 16
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  13. 1
      apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css
  14. 11
      apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css
  15. 53
      apps/remix-ide/src/blockchain/blockchain.js
  16. 11
      apps/remix-ide/src/remixAppManager.js
  17. 2
      apps/solidity-compiler/src/app/compiler-api.ts
  18. 8
      libs/remix-analyzer/package.json
  19. 6
      libs/remix-astwalker/package.json
  20. 2
      libs/remix-core-plugin/src/lib/constants/uups.ts
  21. 8
      libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts
  22. 10
      libs/remix-debug/package.json
  23. 4
      libs/remix-lib/package.json
  24. 6
      libs/remix-simulator/package.json
  25. 6
      libs/remix-solidity/package.json
  26. 10
      libs/remix-tests/package.json
  27. 22
      libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
  28. 4
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  29. 2
      libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx
  30. 2
      libs/remix-ui/search/src/lib/components/Search.tsx
  31. 6
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  32. 2
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  33. 2
      libs/remix-ui/terminal/src/lib/components/RenderUnknownTransactions.tsx
  34. 36
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  35. 2
      libs/remix-ui/workspace/src/lib/css/remix-ui-workspace.css
  36. 3
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  37. 4
      libs/remix-url-resolver/package.json
  38. 4
      libs/remix-ws-templates/package.json
  39. 69
      libs/remixd/README.md
  40. 2
      libs/remixd/package.json
  41. 2
      libs/remixd/src/bin/remixd.ts
  42. 2
      libs/remixd/src/origins.json
  43. 3
      package.json

@ -26,11 +26,11 @@ function testConstantFunction (browser: NightwatchBrowser, address: string, fnFu
done()
})
})
.click('.instance button[title="' + fnFullName + '"]')
.click(`#instance${address} button[title="${fnFullName}"]`)
.pause(1000)
.waitForElementPresent('#instance' + address + ' .udapp_contractActionsContainer .udapp_value')
.scrollInto('#instance' + address + ' .udapp_contractActionsContainer .udapp_value')
.assert.containsText('#instance' + address + ' .udapp_contractActionsContainer .udapp_value', expectedOutput).perform(() => {
.assert.containsText('#instance' + address + ' .udapp_contractActionsContainer', expectedOutput).perform(() => {
cb()
})
}

@ -0,0 +1,287 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
let firstProxyAddress: string
let lastProxyAddress: string
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Should show deploy proxy option for UUPS upgradeable contract': function (browser: NightwatchBrowser) {
browser
.addFile('myTokenV1.sol', sources[0]['myTokenV1.sol'])
.clickLaunchIcon('solidity')
.pause(2000)
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
},
'Should show upgrade proxy option for child contract inheriting UUPS parent contract': function (browser: NightwatchBrowser) {
browser
.addFile('myTokenV2.sol', sources[1]['myTokenV2.sol'])
.clickLaunchIcon('solidity')
.pause(2000)
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
},
'Should deploy proxy without initialize parameters': function (browser: NightwatchBrowser) {
browser
.openFile('myTokenV1.sol')
.clickLaunchIcon('solidity')
.pause(2000)
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.click('[data-id="contractGUIDeployWithProxyLabel"]')
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
},
'Should interact with deployed contract via ERC1967 (proxy)': function (browser: NightwatchBrowser) {
browser
.getAddressAtPosition(1, (address) => {
firstProxyAddress = address
})
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'name - call', null, '0:\nstring: MyToken').perform(() => {
done()
})
})
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'symbol - call', null, '0:\nstring: MTK').perform(() => {
done()
})
})
},
'Should deploy proxy with initialize parameters': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.addFile('initializeProxy.sol', sources[2]['initializeProxy.sol'])
.clickLaunchIcon('solidity')
.pause(2000)
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyInitializedToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyInitializedToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.click('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('input[title="tokenName"]')
.waitForElementPresent('input[title="tokenSymbol"]')
.setValue('input[title="tokenName"]', 'Remix')
.setValue('input[title="tokenSymbol"]', "R")
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
},
'Should interact with initialized contract to verify parameters': function (browser: NightwatchBrowser) {
browser
.getAddressAtPosition(1, (address) => {
lastProxyAddress = address
})
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'name - call', null, '0:\nstring: Remix').perform(() => {
done()
})
})
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'symbol - call', null, '0:\nstring: R').perform(() => {
done()
})
})
},
'Should upgrade contract using last deployed proxy address (MyTokenV1 to MyTokenV2)': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
.clickLaunchIcon('solidity')
.pause(2000)
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
.click('[data-id="contractGUIUpgradeImplementationLabel"]')
.waitForElementPresent('[data-id="contractGUIProxyAddressLabel"]')
.click('[data-id="contractGUIProxyAddressLabel"]')
.waitForElementPresent('[data-id="lastDeployedERC1967Address"]')
.assert.containsText('[data-id="lastDeployedERC1967Address"]', lastProxyAddress)
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
},
'Should interact with upgraded function in contract MyTokenV2': function (browser: NightwatchBrowser) {
browser
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
},
'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2)': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
.clickLaunchIcon('solidity')
.pause(2000)
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
.waitForElementPresent('[data-id="contractGUIProxyAddressLabel"]')
.click('[data-id="contractGUIProxyAddressLabel"]')
.waitForElementPresent('[data-id="ERC1967AddressInput"]')
.setValue('[data-id="ERC1967AddressInput"]', firstProxyAddress)
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
},
'Should interact with upgraded contract through provided proxy address': function (browser: NightwatchBrowser) {
browser
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
.end()
}
}
const sources = [
{
'myTokenV1.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize() initializer public {
__ERC721_init("MyToken", "MTK");
__Ownable_init();
__UUPSUpgradeable_init();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
`
}
}, {
'myTokenV2.sol': {
content: `
import "./myTokenV1.sol";
contract MyTokenV2 is MyToken {
function version () public view returns (string memory) {
return "MyTokenV2!";
}
}
`
}
}, {
'initializeProxy.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyInitializedToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(string memory tokenName, string memory tokenSymbol) initializer public {
__ERC721_init(tokenName, tokenSymbol);
__Ownable_init();
__UUPSUpgradeable_init();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
`
}
}
]

@ -266,8 +266,86 @@ module.exports = {
.waitForElementVisible('[data-id="workspacesSelect"]')
.click('[data-id="workspacesSelect"]')
.waitForElementNotPresent(`[data-id="dropdown-item-workspace_name_1"]`)
.end()
},
// CLONE REPOSITORY E2E START
'Should clone a repository #group2': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('[data-id="cloneGitRepository"]')
.click('[data-id="cloneGitRepository"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]')
.click('[data-id="fileSystemModalDialogModalBody-react"]')
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]')
.setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/awesome-remix')
.click('[data-id="fileSystem-modal-footer-ok-react"]')
.waitForElementPresent('.fa-spinner')
.pause(5000)
.waitForElementNotPresent('.fa-spinner')
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]')
.waitForElementContainsText('[data-id="workspacesSelect"]', 'awesome-remix')
},
'Should display dgit icon for cloned workspace #group2': function (browser: NightwatchBrowser) {
browser
.switchWorkspace('default_workspace')
.waitForElementNotVisible('[data-id="workspacesSelect"] .fa-code-branch')
.switchWorkspace('awesome-remix')
.waitForElementVisible('[data-id="workspacesSelect"] .fa-code-branch')
},
'Should display non-clashing names for duplicate clone #group2': '' + function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('[data-id="cloneGitRepository"]')
.click('[data-id="cloneGitRepository"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]')
.click('[data-id="fileSystemModalDialogModalBody-react"]')
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]')
.setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/awesome-remix')
.click('[data-id="fileSystem-modal-footer-ok-react"]')
.pause(5000)
.waitForElementContainsText('[data-id="workspacesSelect"]', 'awesome-remix1')
.waitForElementVisible('[data-id="cloneGitRepository"]')
.click('[data-id="cloneGitRepository"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]')
.click('[data-id="fileSystemModalDialogModalBody-react"]')
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]')
.setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/awesome-remix')
.click('[data-id="fileSystem-modal-footer-ok-react"]')
.pause(5000)
.waitForElementContainsText('[data-id="workspacesSelect"]', 'awesome-remix2')
.waitForElementVisible('[data-id="cloneGitRepository"]')
.click('[data-id="cloneGitRepository"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]')
.click('[data-id="fileSystemModalDialogModalBody-react"]')
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]')
.setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/awesome-remix')
.click('[data-id="fileSystem-modal-footer-ok-react"]')
.pause(5000)
.waitForElementContainsText('[data-id="workspacesSelect"]', 'awesome-remix3')
.switchWorkspace('awesome-remix')
.switchWorkspace('awesome-remix1')
.switchWorkspace('awesome-remix2')
.switchWorkspace('awesome-remix3')
},
'Should display error message in modal for failed clone #group2': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('[data-id="cloneGitRepository"]')
.click('[data-id="cloneGitRepository"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]')
.click('[data-id="fileSystemModalDialogModalBody-react"]')
.waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]')
.setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/non-existent-repo')
.click('[data-id="fileSystem-modal-footer-ok-react"]')
.pause(5000)
.waitForElementVisible('[data-id="cloneGitRepositoryModalDialogModalBody-react"]')
.waitForElementContainsText('[data-id="cloneGitRepositoryModalDialogModalBody-react"]', 'An error occurred: Please check that you have the correct URL for the repo. If the repo is private, you need to add your github credentials (with the valid token permissions) in Settings plugin')
.click('[data-id="cloneGitRepository-modal-footer-ok-react"]')
.end()
},
// CLONE REPOSITORY E2E END
tearDown: sauce
}

@ -18,7 +18,7 @@ const profile = {
kind: 'compiler',
permission: true,
location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html',
documentation: 'https://remix-ide.readthedocs.io/en/latest/compile.html',
version: packageJson.version,
maintainedBy: 'Remix',
methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig', 'compileFile', 'getCompilerState']

@ -1,9 +1,5 @@
import * as packageJson from '../../../../../package.json'
import { Plugin } from '@remixproject/engine'
import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app'
import React from 'react' // eslint-disable-line
import { Blockchain } from '../../blockchain/blockchain'
import { ethers } from 'ethers'
import { AbstractProvider } from './abstract-provider'
const profile = {
@ -22,10 +18,12 @@ export class FoundryProvider extends AbstractProvider {
body (): JSX.Element {
return (
<div> Note: To run Anvil on your system, run
<div className="border p-1">curl -L https://foundry.paradigm.xyz | bash</div>
<div className="border p-1">anvil</div>
For more info, visit: <a href="https://github.com/foundry-rs/foundry" target="_blank">Foundry Documentation</a>
<div> Note: To run Anvil on your system, run:
<div className="p-1 pl-3"><b>curl -L https://foundry.paradigm.xyz | bash</b></div>
<div className="p-1 pl-3"><b>anvil</b></div>
<div className="pt-2 pb-4">
For more info, visit: <a href="https://github.com/foundry-rs/foundry" target="_blank">Foundry Documentation</a>
</div>
<div>Anvil JSON-RPC Endpoint:</div>
</div>
)

@ -22,10 +22,12 @@ export class GanacheProvider extends AbstractProvider {
body (): JSX.Element {
return (
<div> Note: To run Ganache on your system, run
<div className="border p-1">yarn global add ganache</div>
<div className="border p-1">ganache</div>
For more info, visit: <a href="https://github.com/trufflesuite/ganache" target="_blank">Ganache Documentation</a>
<div> Note: To run Ganache on your system, run:
<div className="p-1 pl-3"><b>yarn global add ganache</b></div>
<div className="p-1 pl-3"><b>ganache</b></div>
<div className="pt-2 pb-4">
For more info, visit: <a href="https://github.com/trufflesuite/ganache" target="_blank">Ganache Documentation</a>
</div>
<div>Ganache JSON-RPC Endpoint:</div>
</div>
)

@ -23,8 +23,10 @@ export class HardhatProvider extends AbstractProvider {
body (): JSX.Element {
return (
<div> Note: To run Hardhat network node on your system, go to hardhat project folder and run command:
<div className="border p-1">npx hardhat node</div>
For more info, visit: <a href="https://hardhat.org/getting-started/#connecting-a-wallet-or-dapp-to-hardhat-network" target="_blank">Hardhat Documentation</a>
<div className="p-1 pl-3"><b>npx hardhat node</b></div>
<div className="pt-2 pb-4">
For more info, visit: <a href="https://hardhat.org/getting-started/#connecting-a-wallet-or-dapp-to-hardhat-network" target="_blank">Hardhat Documentation</a>
</div>
<div>Hardhat JSON-RPC Endpoint:</div>
</div>
)

@ -34,6 +34,7 @@
--dark:#7b8a8b;
--body-bg: #fff;
--text-bg-mark: #fcf8e3;
--custom-select: #fff;
--breakpoint-xs:0;
--breakpoint-sm:576px;
--breakpoint-md:768px;

@ -35,6 +35,7 @@
--dark:#333;
--body-bg:#fff;
--text-bg-mark: #fcf8e3;
--custom-select: #fff;
--breakpoint-xs:0;
--breakpoint-sm:576px;
--breakpoint-md:768px;

@ -23,6 +23,7 @@
--dark: #1a1a1a;
--text: #babbcc;
--body-bg: #1a1a1a;
--custom-select: #252525;
--text-bg-mark: #a5a5a5;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
@ -3639,7 +3640,7 @@ input[type="submit"].btn-block {
.nav-tabs .nav-item.show .nav-link,
.nav-tabs .nav-link.active {
color: #d5d5d5;
background-color: #252525;
background-color: #var(--custom-select);
border-color: #37373B;
font-weight: bolder;
}

@ -23,6 +23,7 @@
--text: #11556c;
--body-bg: #d5efff;
--text-bg-mark: #fcf8e3;
--custom-select: #ffffff;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
@ -3652,7 +3653,7 @@ input[type="button"].btn-block {
line-height: 1.5;
color: #495057;
vertical-align: middle;
background-color: #fffff6;
background-color: var(--custom-select);
background-image: url("data:image/svg+xml,%3Csvg width='8' height='14' viewBox='0 0 8 14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.02426 9.48731C7.18128 9.29086 7.04141 9 6.78992 9L1.21005 9C0.958559 9 0.818689 9.29086 0.975709 9.48731L3.76564 12.9778C3.88574 13.1281 4.11423 13.1281 4.23433 12.9778L7.02426 9.48731Z' fill='%238A93B0'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.02426 4.51269C7.18128 4.70914 7.04141 5 6.78992 5L1.21005 5C0.958559 5 0.818689 4.70914 0.975709 4.51269L3.76564 1.02218C3.88574 0.871926 4.11423 0.871926 4.23433 1.02218L7.02426 4.51269Z' fill='%238A93B0'/%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-size: 8px;

@ -24,6 +24,7 @@
--text: #babbcc;
--text-background: #222336;
--text-bg-mark: #8388b2;
--custom-select: #35384c;
--body-bg: #222336;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
@ -1619,7 +1620,8 @@ pre code {
font-weight: 400;
line-height: 1.25;
color: #dfe1ea !important;
background-color: #35384C !important;
background-color: var(--custom-select)
!important;
background-clip: padding-box;
border: none !important;
border-radius: 2px !important;
@ -1638,7 +1640,8 @@ pre code {
}
.form-control:focus {
color: #dfe1ea;
background-color: #35384c;
background-color: var(--custom-select)
;
border-color: #27c6ff;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
@ -1655,7 +1658,8 @@ pre code {
}
select.form-control:focus::-ms-value {
color: #dfe1ea;
background-color: #35384c;
background-color: var(--custom-select)
;
}
.form-control-file,
.form-control-range {
@ -3357,7 +3361,8 @@ input[type="submit"].btn-block {
}
.custom-select:focus::-ms-value {
color: #dfe1ea;
background-color: #35384c;
background-color: var(--custom-select)
;
}
.custom-select[multiple],
.custom-select[size]:not([size="1"]) {
@ -3425,7 +3430,8 @@ input[type="submit"].btn-block {
font-weight: 400;
line-height: 1.25;
color: #dfe1ea;
background-color: #35384c;
background-color: var(--custom-select)
;
border: 1px solid transparent;
border-radius: 2px;
}

@ -23,6 +23,7 @@
--text: #3b445e;
--body-bg: #eef1f6;
--text-bg-mark: #fcf8e3;
--custom-select: #fff;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;

@ -23,6 +23,7 @@
--text: #11556c;
--body-bg: #DBE2E0;
--text-bg-mark: #fcf8e3;
--custom-select: #eeede9;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
@ -1790,7 +1791,7 @@ pre code {
font-weight: 400;
line-height: 1.5;
color: #495057;
background-color: #dddddd;
background-color: #var(--custom-select);
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 2px !important;
@ -3654,7 +3655,7 @@ input[type="button"].btn-block {
line-height: 1.5;
color: #495057;
vertical-align: middle;
background-color: #dddddd;
background-color: #var(--custom-select);
background-image: url("data:image/svg+xml,%3Csvg width='8' height='14' viewBox='0 0 8 14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.02426 9.48731C7.18128 9.29086 7.04141 9 6.78992 9L1.21005 9C0.958559 9 0.818689 9.29086 0.975709 9.48731L3.76564 12.9778C3.88574 13.1281 4.11423 13.1281 4.23433 12.9778L7.02426 9.48731Z' fill='%238A93B0'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7.02426 4.51269C7.18128 4.70914 7.04141 5 6.78992 5L1.21005 5C0.958559 5 0.818689 4.70914 0.975709 4.51269L3.76564 1.02218C3.88574 0.871926 4.11423 0.871926 4.23433 1.02218L7.02426 4.51269Z' fill='%238A93B0'/%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-size: 8px;
@ -3775,13 +3776,13 @@ input[type="button"].btn-block {
outline: none;
}
.custom-range:focus::-webkit-slider-thumb {
box-shadow: 0 0 0 1px #dddddd, 0px 0px 5px #00bbff;
box-shadow: 0 0 0 1px #var(--custom-select), 0px 0px 5px #00bbff;
}
.custom-range:focus::-moz-range-thumb {
box-shadow: 0 0 0 1px #dddddd, 0px 0px 5px #00bbff;
box-shadow: 0 0 0 1px #var(--custom-select), 0px 0px 5px #00bbff;
}
.custom-range:focus::-ms-thumb {
box-shadow: 0 0 0 1px #dddddd, 0px 0px 5px #00bbff;
box-shadow: 0 0 0 1px #var(--custom-select), 0px 0px 5px #00bbff;
}
.custom-range::-moz-focus-outer {
border: 0;

@ -617,30 +617,43 @@ export class Blockchain extends Plugin {
const timestamp = tx.timestamp
this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb,
async (error, result) => {
if (error) return reject(error)
const isVM = this.executionContext.isVM()
if (isVM && tx.useCall) {
try {
result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp)
} catch (e) {
console.log('unable to retrieve back the "call" hash', e)
try {
this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb,
async (error, result) => {
if (error) {
if (typeof (error) !== 'string') {
if (error.message) error = error.message
else {
try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) }
}
}
return reject(error)
}
}
const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted')
this.event.trigger(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad])
if (error && (typeof (error) !== 'string')) {
if (error.message) error = error.message
else {
try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) }
const isVM = this.executionContext.isVM()
if (isVM && tx.useCall) {
try {
result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp)
} catch (e) {
console.log('unable to retrieve back the "call" hash', e)
}
}
const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted')
this.event.trigger(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad])
return resolve({ result, tx })
}
)
} catch (err) {
let error = err
if (error && (typeof (error) !== 'string')) {
if (error.message) error = error.message
else {
try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) }
}
return resolve({ result, tx })
}
)
return reject(error)
}
})
}
try {

@ -4,14 +4,17 @@ import { QueryParams } from '@remix-project/remix-lib'
import { IframePlugin } from '@remixproject/engine-web'
const _paq = window._paq = window._paq || []
// requiredModule removes the plugin from the plugin manager list on UI
const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'locale',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy',
'hardhat-provider', 'compileAndRun', 'search', 'recorder']
'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider',
'compileAndRun', 'search', 'recorder']
const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['hardhat', 'truffle', 'slither']
const sensitiveCalls = {
'fileManager': ['writeFile', 'copyFile', 'rename', 'copyDir'],
@ -20,7 +23,9 @@ const sensitiveCalls = {
}
export function isNative(name) {
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider']
// nativePlugin allows to bypass the permission request
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting',
'layout', 'notification', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider']
return nativePlugins.includes(name) || requiredModules.includes(name)
}

@ -298,7 +298,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
this.compilationDetails = {
contractMap: {},
contractsDetails: {},
target: source.target
target: source ? source.target : null
}
}
if (this.onCompilationFinished) this.onCompilationFinished(this.compilationDetails)

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.23",
"version": "0.5.24",
"description": "Tool to perform static analysis on Solidity smart contracts",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -22,8 +22,8 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.44",
"@remix-project/remix-lib": "^0.5.14",
"@remix-project/remix-astwalker": "^0.0.45",
"@remix-project/remix-lib": "^0.5.15",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
@ -52,5 +52,5 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
"version": "0.0.44",
"version": "0.0.45",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.14",
"@remix-project/remix-lib": "^0.5.15",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
@ -54,5 +54,5 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

File diff suppressed because one or more lines are too long

@ -1,5 +1,5 @@
import { Plugin } from '@remixproject/engine'
import { ContractABI, ContractAST, ContractSources, DeployOptions } from '../types/contract'
import { ContractAST, ContractSources, DeployOptions } from '../types/contract'
import { UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi, UUPSupgradeAbi } from './constants/uups'
const proxyProfile = {
@ -18,7 +18,9 @@ export class OpenZeppelinProxy extends Plugin {
async isConcerned(ast: ContractAST = {} as ContractAST): Promise<boolean> {
// check in the AST if it's an upgradable contract
if (ast.nodes && ast.nodes.find(node => node.absolutePath && node.absolutePath.includes(UUPS))) {
const UUPSSymbol = ast.exportedSymbols && ast.exportedSymbols[UUPS] ? ast.exportedSymbols[UUPS][0] : null
if (UUPSSymbol) {
this.kind = 'UUPS'
return true
}
@ -36,7 +38,7 @@ export class OpenZeppelinProxy extends Plugin {
if (this.kind === 'UUPS') {
Object.keys(contracts).map(name => {
if (ast) {
const UUPSSymbol = ast.exportedSymbols['UUPSUpgradeable'] ? ast.exportedSymbols['UUPSUpgradeable'][0] : null
const UUPSSymbol = ast.exportedSymbols[UUPS] ? ast.exportedSymbols[UUPS][0] : null
ast.absolutePath === file && ast.nodes.map((node) => {
if (node.name === name && node.linearizedBaseContracts.includes(UUPSSymbol)) {

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
"version": "0.5.14",
"version": "0.5.15",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@ -22,9 +22,9 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.44",
"@remix-project/remix-lib": "^0.5.14",
"@remix-project/remix-simulator": "^0.2.14",
"@remix-project/remix-astwalker": "^0.0.45",
"@remix-project/remix-lib": "^0.5.15",
"@remix-project/remix-simulator": "^0.2.15",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -68,5 +68,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
"version": "0.5.14",
"version": "0.5.15",
"description": "Library to various Remix tools",
"contributors": [
{
@ -54,5 +54,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
"version": "0.2.14",
"version": "0.2.15",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@ -18,7 +18,7 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.14",
"@remix-project/remix-lib": "^0.5.15",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@ -67,5 +67,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
"version": "0.5.0",
"version": "0.5.1",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -18,7 +18,7 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.14",
"@remix-project/remix-lib": "^0.5.15",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethereumjs-util": "^7.0.10",
@ -61,5 +61,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
"version": "0.2.14",
"version": "0.2.15",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@ -39,9 +39,9 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.14",
"@remix-project/remix-simulator": "^0.2.14",
"@remix-project/remix-solidity": "^0.5.0",
"@remix-project/remix-lib": "^0.5.15",
"@remix-project/remix-simulator": "^0.2.15",
"@remix-project/remix-solidity": "^0.5.1",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
"axios": ">=0.21.1",
@ -79,5 +79,5 @@
"typescript": "^3.3.1"
},
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -12,6 +12,7 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
useEffect(() => {
setToggleExpander(false)
if (props.plugins) {
const p = Object.values(props.plugins).find((pluginRecord) => {
return pluginRecord.active === true
@ -26,22 +27,21 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
return (
<header className='d-flex flex-column'>
<div className="swapitHeader px-3 pt-3 pb-0 d-flex flex-row">
<h6 data-id='sidePanelSwapitTitle'>
{/* @ts-ignore */}
<FormattedMessage id={plugin?.profile.intlId || 'defaultId'} defaultMessage={plugin?.profile.displayName || plugin?.profile.name} />
</h6>
<div className="d-flex flex-row">
<div className="swapitHeader px-3 pt-2 pb-0 d-flex flex-row">
<h6 className="mb-2" data-id='sidePanelSwapitTitle'>
{/* @ts-ignore */}
<FormattedMessage id={plugin?.profile.intlId || 'defaultId'} defaultMessage={plugin?.profile.displayName || plugin?.profile.name} />
</h6>
<div className="mt-2 d-flex flex-row">
<div className="d-flex flex-row">
{plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && (<i aria-hidden="true" className="text-success fas fa-check" title="Maintained by Remix"></i>)}
{plugin?.profile.documentation && (<a href={plugin.profile.documentation} className="titleInfo mb-2" title="link to documentation" target="_blank" rel="noreferrer"><i aria-hidden="true" className="fas fa-book"></i></a>)}
{plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && (<i aria-hidden="true" className="text-success mt-1 px-1 fas fa-check" title="Maintained by Remix"></i>)}
</div>
<div className="swapitHeaderInfoSection d-flex justify-content-between" data-id='swapitHeaderInfoSectionId' onClick={toggleClass} title="Plugin info">
<i className={`px-2 ml-2 pt-1 ${!toggleExpander ? 'fas fa-angle-right' : 'fas fa-angle-down bg-light'}`} aria-hidden="true"></i>
<i className={`px-2 ml-2 pt-1 pb-4 ${!toggleExpander ? 'fas fa-angle-right' : 'fas fa-angle-down bg-light'}`} aria-hidden="true"></i>
</div>
</div>
</div>
<div className={`bg-light p-3 pt-1 border-bottom flex-column ${toggleExpander ? "d-flex" : "d-none"}`}>
<div className={`bg-light mx-3 mb-2 p-3 pt-1 border-bottom flex-column ${toggleExpander ? "d-flex" : "d-none"}`}>
{plugin?.profile?.author && <span className="d-flex flex-row align-items-center">
<label className="mb-0 pr-2">Author:</label>
<span> { plugin?.profile.author } </span>
@ -53,7 +53,7 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
{plugin?.profile?.documentation && <span className="d-flex flex-row align-items-center">
<label className="mb-0 pr-2">Documentation:</label>
<span>
<a href={plugin?.profile?.documentation} className="titleInfo mb-2" title="link to documentation" target="_blank" rel="noreferrer"><i aria-hidden="true" className="fas fa-book"></i></a>
<a href={plugin?.profile?.documentation} className="titleInfo p-0 mb-2" title="link to documentation" target="_blank" rel="noreferrer"><i aria-hidden="true" className="fas fa-book"></i></a>
</span>
</span>}
{plugin?.profile?.description && <span className="d-flex flex-row align-items-baseline">

@ -348,9 +348,9 @@ export function ContractGUI (props: ContractGUIProps) {
!useLastProxy ?
<div className="mb-2">
<label className='mt-2 text-left d-block'>Proxy Address: </label>
<input style={{ height: 32 }} className="form-control udapp_input" placeholder='proxy address' title='Enter previously deployed proxy address on the selected network' onChange={handleSetProxyAddress} />
<input style={{ height: 32 }} className="form-control udapp_input" data-id="ERC1967AddressInput" placeholder='proxy address' title='Enter previously deployed proxy address on the selected network' onChange={handleSetProxyAddress} />
</div> :
<span className='text-capitalize' style={{ fontSize: '.8em' }}>{ proxyAddress || 'No proxy address available' }</span>
<span className='text-capitalize' data-id="lastDeployedERC1967Address" style={{ fontSize: '.8em' }}>{ proxyAddress || 'No proxy address available' }</span>
}
</div>
</div>

@ -18,7 +18,7 @@ export function RecorderUI (props: RecorderProps) {
}
useEffect(() => {
if (props.currentFile.endsWith('.json')) setEnableRunButton(false)
if (props.currentFile && props.currentFile.endsWith('.json')) setEnableRunButton(false)
else setEnableRunButton(true)
}, [props.currentFile])

@ -13,7 +13,7 @@ export const SearchTab = props => {
return (
<>
<div className="search_plugin_search_tab px-2 pb-4">
<div className="search_plugin_search_tab pr-4 px-2 pb-4">
<SearchProvider plugin={plugin}>
<FindContainer></FindContainer>
<Include></Include>

@ -378,6 +378,8 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const compilerToLoad = semver.maxSatisfying(releasedVersions, pragma)
const compilerPath = state.allversions.filter(obj => !obj.prerelease && obj.version === compilerToLoad)[0].path
if (state.selectedVersion !== compilerPath) {
// @ts-ignore
api.call('notification', 'toast', `Updating compiler version to match current contract file pragma i.e ${_retrieveVersion(compilerPath)}`)
setState((prevState) => {
return { ...prevState, selectedVersion: compilerPath }
})
@ -753,7 +755,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/hardhat.html#enable-hardhat-compilation' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip-hardhat">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>
<span className="border bg-light text-dark p-1 pr-3" style={{ minWidth: '230px' }}>
<FormattedMessage id='solidity.learnHardhat' defaultMessage='Learn how to use Hardhat Compilation' />
</span>
</Tooltip>
@ -773,7 +775,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/truffle.html#enable-truffle-compilation' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip-truffle">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>
<span className="border bg-light text-dark p-1 pr-3" style={{ minWidth: '230px' }}>
<FormattedMessage id='solidity.learnTruffle' defaultMessage='Learn how to use Truffle Compilation' />
</span>
</Tooltip>

@ -490,7 +490,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/slither.html#enable-slither-analysis' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Slither Analysis</span>
<span className="border bg-light text-dark p-1 pr-3" style={{minWidth: '230px' }}>Learn how to use Slither Analysis</span>
</Tooltip>
}>
<i style={{ fontSize: 'medium' }} className={'fal fa-info-circle ml-3'} aria-hidden="true"></i>

@ -33,7 +33,7 @@ const RenderUnKnownTransactions = ({ tx, receipt, index, plugin, showTableHash,
</div>
{showTableHash.includes(tx.hash) ? showTable({
hash: tx.hash,
status: receipt !== null ? receipt.status : null,
status: receipt ? receipt.status : null,
isCall: tx.isCall,
contractAddress: tx.contractAddress,
data: tx,

@ -2,7 +2,7 @@ import React from 'react'
import { bufferToHex, keccakFromString } from 'ethereumjs-util'
import axios, { AxiosResponse } from 'axios'
import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace } from './payload'
import { checkSlash, checkSpecialChars, createNonClashingTitle } from '@remix-ui/helper'
import { checkSlash, checkSpecialChars } from '@remix-ui/helper'
import { JSONStandardInput, WorkspaceTemplate } from '../types'
import { QueryParams } from '@remix-project/remix-lib'
@ -245,9 +245,9 @@ export const switchToWorkspace = async (name: string) => {
dispatch(setMode('localhost'))
plugin.emit('setWorkspace', { name: null, isLocalhost: true })
} else if (name === NO_WORKSPACE) {
await plugin.fileProviders.workspace.clearWorkspace()
await plugin.setWorkspace({ name: null, isLocalhost: false })
dispatch(setCurrentWorkspace(null))
// if there is no other workspace, create remix default workspace
plugin.call('notification', 'toast', `No workspace found! Creating default workspace ....`)
await createWorkspace('default_workspace', 'remixDefault')
} else {
const isActive = await plugin.call('manager', 'isActive', 'remixd')
@ -333,11 +333,10 @@ export const cloneRepository = async (url: string) => {
const config = plugin.registry.get('config').api
const token = config.get('settings/gist-access-token')
const repoConfig = { url, token }
const urlArray = url.split('/')
let repoName = urlArray.length > 0 ? urlArray[urlArray.length - 1] : ''
try {
repoName = await createNonClashingTitle(repoName, plugin.fileManager)
const repoName = await getRepositoryTitle(url)
await createWorkspace(repoName, 'blank', true, null, true)
const promise = plugin.call('dGitProvider', 'clone', repoConfig, repoName, true)
@ -348,11 +347,11 @@ export const cloneRepository = async (url: string) => {
if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit')
await fetchWorkspaceDirectory(repoName)
dispatch(cloneRepositorySuccess())
}).catch((e) => {
}).catch(() => {
const cloneModal = {
id: 'cloneGitRepository',
title: 'Clone Git Repository',
message: 'An error occured: ' + e,
message: 'An error occurred: Please check that you have the correct URL for the repo. If the repo is private, you need to add your github credentials (with the valid token permissions) in Settings plugin',
modalType: 'modal',
okLabel: 'OK',
okFn: async () => {
@ -370,3 +369,22 @@ export const cloneRepository = async (url: string) => {
dispatch(displayPopUp('An error occured: ' + e))
}
}
export const getRepositoryTitle = async (url: string) => {
const urlArray = url.split('/')
let name = urlArray.length > 0 ? urlArray[urlArray.length - 1] : ''
if (!name) name = 'Undefined'
let _counter
let exist = true
do {
const isDuplicate = await workspaceExists(name + (_counter || ''))
if (isDuplicate) _counter = (_counter || 0) + 1
else exist = false
} while (exist)
const counter = _counter || ''
return name + counter
}

@ -88,7 +88,7 @@
.custom-dropdown-items {
padding: 0.25rem 0.25rem;
border-radius: .25rem;
background: var(--light);
background: var(--custom-select);
}
.custom-dropdown-items a {
border-radius: .25rem;

@ -196,7 +196,7 @@ export function Workspace () {
}
return (
<div className='remixui_container'>
<div className='px-2 remixui_container'>
<div className='remixui_fileexplorer' data-id="remixUIWorkspaceExplorer" onClick={resetFocus}>
<div>
<header>
@ -261,6 +261,7 @@ export function Workspace () {
title={intl.formatMessage({id: 'filePanel.workspace.restore', defaultMessage: 'Restore Workspaces Backup'})}>
</span>
<span
hidden={currentWorkspace === LOCALHOST}
id='cloneGitRepository'
data-id='cloneGitRepository'
onClick={(e) => {

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-url-resolver",
"version": "0.0.35",
"version": "0.0.36",
"description": "Solidity import url resolver engine",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -41,5 +41,5 @@
"typescript": "^3.1.6"
},
"typings": "src/index.d.ts",
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-ws-templates",
"version": "1.0.1",
"version": "1.0.2",
"description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -25,5 +25,5 @@
"ethers": "^5.4.2",
"web3": "^1.5.1"
},
"gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71"
"gitHead": "714a13ef29c4c5b018e25b49270809f2ea456b08"
}

@ -1,59 +1,88 @@
# Remixd
`remixd` is a tool that intend to be used with [Remix IDE](https://github.com/ethereum/remix-project) (aka. Browser-Solidity). It allows a websocket connection between
`Remix IDE` (web application) and the local computer.
[![npm version](https://badge.fury.io/js/%40remix-project%2Fremixd.svg)](https://www.npmjs.com/package/@remix-project/remixd)
[![npm](https://img.shields.io/npm/dt/@remix-project/remixd.svg?label=Total%20Downloads&logo=npm)](https://www.npmjs.com/package/@remix-project/remixd)
[![npm](https://img.shields.io/npm/dw/@remix-project/remixd.svg?logo=npm)](https://www.npmjs.com/package/@remix-project/remixd)
Practically Remix IDE makes available a folder shared by `remixd`.
More details are explained in this [tutorial](https://remix-ide.readthedocs.io/en/latest/remixd.html).
`@remix-project/remixd` is an NPM module that intends to be used with [Remix IDE](https://remix.ethereum.org/) web and desktop applications. It establishes a two-way websocket connection between the local computer and Remix IDE for a particular project directory.
Alternatively `remixd` can be used to setup a development environment that can be used with other popular frameworks like Embark, Truffle, Ganache, etc..
`remixd` can be used to setup a development environment with other popular frameworks like Hardhat, Truffle, Slither etc.
`remixd` needs `npm` and `node`
More details are explained in the [documentation](https://remix-ide.readthedocs.io/en/latest/remixd.html).
## INSTALLATION
## Installation
`yarn global add @remix-project/remixd`
`npm install -g @remix-project/remixd`
### Warning for old users
NOTE: When the remixd NPM module is installed, it also installs [Slither](https://github.com/crytic/slither), [solc-select](https://github.com/crytic/solc-select#quickstart) and sets [solc](https://docs.soliditylang.org/en/latest/installing-solidity.html) to latest version i.e. 0.8.15 currently.
ALSO NOTE: Python3.6+ (pip3) needs to already be installed on the System. In case of any discrepany, Slither can also installed along with other dependencies using command:
```
> remixd -i slither
```
_(This packaging of Slither with the remixd module is supported since Remixd v0.6.3)_
### Warning for quite old users
There is a new version of remixd with a new npm address: https://npmjs.com/package/@remix-project/remixd
If you were using the old one you need to:
1. uninstall the old one: `npm uninstall -g remixd`
2. install the new: `yarn global add @remix-project/remixd`
2. install the new: `npm install -g @remix-project/remixd`
## remixd command
## HELP SECTION
The remixd command without options shares present working directory and the shared Remix domain will be https://remix.ethereum.org, https://remix-alpha.ethereum.org, or https://remix-beta.ethereum.org
The remixd command is:
```
> remixd
```
Usage: remixd -s <shared folder>
Provide a two-way connection between the local computer and Remix IDE
If you are using Remix from localhost or you are not running the command from your working directory, you’ll need to use the command with flags.
```
> remixd -h
Usage: remixd [options]
Establish a two-way websocket connection between the local computer and Remix IDE for a folder
Options:
-v, --version output the version number
-u, --remix-ide <url> URL of remix instance allowed to connect to this web sockect connection
-s, --shared-folder <path> Folder to share with Remix IDE
-u, --remix-ide <url> URL of remix instance allowed to connect
-s, --shared-folder <path> Folder to share with Remix IDE (Default: CWD)
-i, --install <name> Module name to install locally (Supported: ["slither"])
-r, --read-only Treat shared folder as read-only (experimental)
-h, --help output usage information
Example:
remixd -s ./ -u http://localhost:8080
remixd -s ./shared_project -u http://localhost:8080
```
## SHARE A FOLDER
## Share a project directory
`remixd -s <absolute-path> --remix-ide https://remix.ethereum.org`
`remixd -s ./shared_project -u https://remix.ethereum.org`
The current user should have `read/write` access to the folder (at least `read` access).
It is important to notice that changes made to the current file in `Remix IDE` are automatically saved to the local computer every 5000 ms. There is no `Save` action. But the `Ctrl-Z` (undo) can be used.
Furthermore :
Furthermore:
- No copy of the shared folder are kept in the browser storage.
- It is not possible to create a file from `Remix IDE` (that might change).
- Clicking on the new folder or new file icon under localhost will create a new file or folder in the shared folder.
- If a folder does not contain any file, the folder will not be displayed in the explorer (that might change).
- Symbolic links are not forwarded to Remix IDE.
## Ports Usage
remixd creates a websocket connections with Remix IDE on different ports. Ports are defined according to specific purpose. Port usage details are as:
- **65520** : For `remixd` websocket listener, to share a project from local device with Remix IDE. Shared folder will be loaded in the Remix IDE File Explorer workspace named localhost [See more](https://remix-ide.readthedocs.io/en/latest/remixd.html)
- **65522** : For `Hardhat` websocket listener, to enable the Hardhat Compilation using Remix IDE Solidity Compiler plugin, if shared folder is a Hardhat project [See more](https://remix-ide.readthedocs.io/en/latest/hardhat.html)
- **65523** : For `Slither` websocket listener, to enable the Slither Analysis using Remix IDE Solidity Static Analysis plugin [See more](https://remix-ide.readthedocs.io/en/latest/slither.html)
- **65524** : For `Truffle` websocket listener, to enable the Truffle Compilation using Remix IDE Solidity Compiler plugin, if shared folder is a Truffle project [See more](https://remix-ide.readthedocs.io/en/latest/truffle.html)
Note: Please make sure your system is secured enough and these ports are not opened nor forwarded.

@ -1,6 +1,6 @@
{
"name": "@remix-project/remixd",
"version": "0.6.3",
"version": "0.6.4",
"description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)",
"main": "index.js",
"types": "./index.d.ts",

@ -166,7 +166,7 @@ function errorHandler (error: any, service: string) {
async function isValidOrigin (origin: string): Promise<any> {
if (!origin) return false
const domain = getDomain(origin)
const gistUrl = 'https://gist.githubusercontent.com/EthereumRemix/091ccc57986452bbb33f57abfb13d173/raw/3367e019335746b73288e3710af2922d4c8ef5a3/origins.json'
const gistUrl = 'https://gist.githubusercontent.com/EthereumRemix/091ccc57986452bbb33f57abfb13d173/raw/59cedab38ae94cc72b68854b3706f11819e4a0af/origins.json'
try {
const { data } = (await Axios.get(gistUrl)) as { data: any }

@ -1,8 +1,10 @@
{
"data":[
"http://remix-alpha.ethereum.org",
"http://remix-beta.ethereum.org",
"http://remix.ethereum.org",
"https://remix-alpha.ethereum.org",
"https://remix-beta.ethereum.org",
"https://remix.ethereum.org",
"package://a7df6d3c223593f3550b35e90d7b0b1f.mod",
"package://6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod",

@ -1,6 +1,6 @@
{
"name": "remix-project",
"version": "0.25.0-dev",
"version": "0.26.0-dev",
"license": "MIT",
"description": "Ethereum Remix Monorepo",
"keywords": [
@ -96,6 +96,7 @@
"nightwatch_local_verticalIconscontextmenu": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/verticalIconsPanel.test.js --env=chrome",
"nightwatch_local_pluginApi": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/plugin_api_*.js --env=chrome",
"nightwatch_local_migrate_filesystem": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/migrateFileSystem.test.js --env=chrome",
"nightwatch_local_proxy": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/proxy.test.js --env=chrome",
"nightwatch_local_stress_editor": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/stressEditor.test.js --env=chromeDesktop",
"nightwatch_local_search": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/search.test.js --env=chromeDesktop",
"nightwatch_local_providers": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/providers.test.js --env=chromeDesktop",

Loading…
Cancel
Save