Merge pull request #4841 from ethereum/get-solidity-version-patch

Fix get solidity version for udapp docs
pull/4876/head
Joseph Izang 5 months ago committed by GitHub
commit eefc40a005
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 44
      apps/remix-ide-e2e/src/tests/file_explorer_context_menu.test.ts
  2. 159
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  3. 3
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  4. 6
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  5. 4
      libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx
  6. 22
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  7. 21
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  8. 14
      libs/remix-ui/run-tab/src/lib/types/index.ts

@ -105,25 +105,25 @@ module.exports = {
.click('*[data-id="contextMenuItempaste"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/Copy_README.txt"]', 7000)
},
// folder copy paste tests
'Should copy folder and paste in root with right click and it will contain a copied folder #group1 ': function (browser: NightwatchBrowser) {
browser
.rightClick('li[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementPresent('[data-id="contextMenuItemcopy')
.click('[data-id="contextMenuItemcopy"]')
.rightClick('*[data-id="treeViewLiMenu"]')
.click('*[data-id="contextMenuItempaste"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemCopy_contracts"]', 7000)
},
'Should copy folder and paste in contracts with right click and it will contain a copied folder #group1 ': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.waitForElementVisible('li[data-id="treeViewLitreeViewItemscripts"]')
.rightClick('li[data-id="treeViewLitreeViewItemscripts"]')
.waitForElementPresent('[data-id="contextMenuItemcopy')
.click('[data-id="contextMenuItemcopy"]')
.rightClick('*[data-id="treeViewLitreeViewItemcontracts"]')
.click('*[data-id="contextMenuItempaste"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/Copy_scripts"]', 7000)
}
}
// folder copy paste tests
'Should copy folder and paste in root with right click and it will contain a copied folder #group1 ': function (browser: NightwatchBrowser) {
browser
.rightClick('li[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementPresent('[data-id="contextMenuItemcopy')
.click('[data-id="contextMenuItemcopy"]')
.rightClick('*[data-id="treeViewLiMenu"]')
.click('*[data-id="contextMenuItempaste"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemCopy_contracts"]', 7000)
},
'Should copy folder and paste in contracts with right click and it will contain a copied folder #group1 ': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.waitForElementVisible('li[data-id="treeViewLitreeViewItemscripts"]')
.rightClick('li[data-id="treeViewLitreeViewItemscripts"]')
.waitForElementPresent('[data-id="contextMenuItemcopy')
.click('[data-id="contextMenuItemcopy"]')
.rightClick('*[data-id="treeViewLitreeViewItemcontracts"]')
.click('*[data-id="contextMenuItempaste"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/Copy_scripts"]', 7000)
}
}

@ -167,7 +167,7 @@ module.exports = {
},
'Should print hardhat logs #group4': function (browser: NightwatchBrowser) {
browser
.addFile('printHardhatlog.sol', { content: hardhatLog })
.addFile('printHardhatlog.sol', { content: hardhatLog })
.clickLaunchIcon('solidity')
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.waitForElementVisible('[for="autoCompile"]')
@ -266,22 +266,22 @@ module.exports = {
if (Array.isArray(result.value) && result.value.length > 0) {
console.log('Found ' + result.value.length + ' transactions')
browser
.click({
selector: '[data-id="listenNetworkCheckInput"]',
})
.click({
selector: '*[data-id="terminalClearConsole"]',
})
.click({
selector: '*[data-id="compilerContainerCompileAndRunBtn"]',
})
.pause(10000)
.waitForElementNotPresent({
locateStrategy: 'xpath',
selector: "//*[@class='remix_ui_terminal_log' and contains(.,'to:') and contains(.,'from:')]",
timeout: 120000
})
.end()
.click({
selector: '[data-id="listenNetworkCheckInput"]',
})
.click({
selector: '*[data-id="terminalClearConsole"]',
})
.click({
selector: '*[data-id="compilerContainerCompileAndRunBtn"]',
})
.pause(10000)
.waitForElementNotPresent({
locateStrategy: 'xpath',
selector: "//*[@class='remix_ui_terminal_log' and contains(.,'to:') and contains(.,'from:')]",
timeout: 120000
})
.end()
} else {
browser
.assert.fail('No transaction found')
@ -309,7 +309,7 @@ module.exports = {
.switchEnvironment('vm-custom-fork')
.waitForElementVisible('[data-id="vm-custom-fork-modal-footer-ok-react"]')
.execute(() => {
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus()
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus()
}, [], () => { })
.clearValue('*[data-id="CustomForkNodeUrl"]').pause(1000).setValue('*[data-id="CustomForkNodeUrl"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9')
.execute(() => {
@ -331,7 +331,7 @@ module.exports = {
.executeScriptInTerminal(`web3.eth.getCode('0x75F509A4eDA030470272DfBAf99A47D587E76709')`) // sepolia contract
.waitForElementContainsText('*[data-id="terminalJournal"]', byteCodeInSepolia, 120000)
.click('*[data-id="terminalClearConsole"]')
},
},
'Should run a free function while being connected to mainnet #group9': function (browser: NightwatchBrowser) {
const script = `
@ -359,10 +359,10 @@ module.exports = {
.switchEnvironment('vm-mainnet-fork')
.clickLaunchIcon('filePanel')
.addFile('test_mainnet.sol', { content: script })
const path = "//*[@class='view-line' and contains(.,'resolveENS') and contains(.,'view')]//span//span[contains(.,'(')]"
const path = "//*[@class='view-line' and contains(.,'resolveENS') and contains(.,'view')]//span//span[contains(.,'(')]"
const pathRunFunction = `//li//*[@aria-label='Run the free function "resolveENS"']`
browser.waitForElementVisible('#editorView')
browser.waitForElementVisible('#editorView')
//.waitForElementPresent(pathRunFunction)
.pause(10000) // the parser need to parse the code
.useXpath()
@ -371,25 +371,25 @@ module.exports = {
.perform(function () {
const actions = this.actions({ async: true });
return actions
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('r')
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('r')
})
.useCss()
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 120000)
},
'Should run free function which logs in the terminal #group10': function (browser: NightwatchBrowser) {
const script = `import "hardhat/console.sol";
function runSomething () view {
console.log("test running free function");
}
}
`
browser
.addFile('test.sol', { content: script })
.scrollToLine(3)
const path = "//*[@class='view-line' and contains(.,'runSomething') and contains(.,'view')]//span//span[contains(.,'(')]"
const path = "//*[@class='view-line' and contains(.,'runSomething') and contains(.,'view')]//span//span[contains(.,'(')]"
const pathRunFunction = `//li//*[@aria-label='Run the free function "runSomething"']`
browser.waitForElementVisible('#editorView')
.useXpath()
@ -398,18 +398,15 @@ module.exports = {
.perform(function () {
const actions = this.actions({ async: true });
return actions
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('r')
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('r')
})
.useCss()
.waitForElementContainsText('*[data-id="terminalJournal"]', 'test running free function', 120000)
}
}
const asyncAwait = `
var p = function () {
return new Promise(function (resolve, reject) {
@ -417,7 +414,7 @@ const asyncAwait = `
resolve("Promise Resolved")
}, 5000)
})
}
}
var run = async () => {
console.log('Waiting Promise')
@ -455,7 +452,7 @@ const resolveExternalUrlAndSave = `
} catch (e) {
console.log(e.message)
}
})()
})()
`
const resolveExternalUrlAndSaveToaPath = `
@ -466,7 +463,7 @@ const resolveExternalUrlAndSaveToaPath = `
} catch (e) {
console.log(e.message)
}
})()
})()
`
const resolveUrl = `
@ -477,7 +474,7 @@ const resolveUrl = `
} catch (e) {
console.log(e.message)
}
})()
})()
`
const deployWithEthersJs = `
@ -485,32 +482,32 @@ const deployWithEthersJs = `
(async () => {
try {
console.log('Running deployWithEthers script...')
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = 'contracts/artifacts/Owner.json' // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer)
let contract = await factory.deploy(...constructorArgs);
console.log('Contract Address: ', contract.address);
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
console.log('Deployment successful.')
contract.on('OwnerSet', (previousOwner, newOwner) => {
console.log('previousOwner' , previousOwner)
console.log('newOwner' , newOwner)
})
console.log('ok')
} catch (e) {
console.log(e.message)
@ -577,12 +574,12 @@ contract StorageWithLib {
* @dev Store valrue in variable
* @param num value to store
*/
function store(uint256 num) public {
number = num;
function store(uint256 num) public {
number = num;
}
/**
* @dev Return value
* @dev Return value
* @return value of 'number'
*/
function retrieve() public view returns (uint256){
@ -629,11 +626,11 @@ describe("Storage", function () {
deployedLinkReferences: metadata.data.deployedBytecode.linkReferences,
}
const options = {
libraries: {
libraries: {
'Lib': lib.address
}
}
const factory = await ethers.getContractFactoryFromArtifact(artifact, options)
const storage = await factory.deploy();
await storage.deployed()
@ -657,10 +654,10 @@ import "hardhat/console.sol";
contract OwnerTest {
address private owner;
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
@ -671,7 +668,7 @@ contract OwnerTest {
require(msg.sender == owner, "Caller is not owner");
_;
}
/**
* @dev Set contract deployer as owner
*/
@ -692,7 +689,7 @@ contract OwnerTest {
}
/**
* @dev Return owner address
* @dev Return owner address
* @return address of owner
*/
function getOwner() external view returns (address) {
@ -705,39 +702,39 @@ const scriptAutoExec = {
contract: `// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
library lib {
function test () public view returns (uint) {
return 147;
}
}
/**
* @title Storage
* @dev Store & retrieve value inr a variable
* @custom:dev-run-script ./scripts/deploy_storage.js
*/
contract Storage {
uint256 number;
/**
* @dev Store valrue in variable
* @param num value to store
*/
function store(uint256 num) public {
number = num;
number = num;
}
/**
* @dev Return value
* @dev Return value
* @return value of 'number'
*/
function retrieve() public view returns (uint256){
return number;
}
function getFromLib() public view returns (uint) {
return lib.test();
}
@ -747,16 +744,16 @@ const scriptAutoExec = {
// Right click on the script name and hit "Run" to execute
const { expect } = require("chai");
const { ethers } = require("hardhat");
(async () => {
try {
// function getContractFactoryFromArtifact(artifact: Artifact, signer?: ethers.Signer): Promise<ethers.ContractFactory>;
// function getContractFactoryFromArtifact(artifact: Artifact, factoryOptions: FactoryOptions): Promise<ethers.ContractFactory>;
const metadataLib = JSON.parse(await remix.call('fileManager', 'readFile', 'contracts/artifacts/lib.json'))
console.log('deploying lib:')
const artifactLib = {
contractName: 'Lib',
sourceName: 'contracts/1_Storage.sol',
@ -767,15 +764,15 @@ const scriptAutoExec = {
deployedLinkReferences: metadataLib.data.deployedBytecode.linkReferences,
}
const optionsLib = {}
const factoryLib = await ethers.getContractFactoryFromArtifact(artifactLib, optionsLib)
const lib = await factoryLib.deploy();
await lib.deployed()
console.log('lib deployed', lib.address)
const metadata = JSON.parse(await remix.call('fileManager', 'readFile', 'contracts/artifacts/Storage.json'))
const artifact = {
contractName: 'Storage',
@ -787,25 +784,25 @@ const scriptAutoExec = {
deployedLinkReferences: metadata.data.deployedBytecode.linkReferences,
}
const options = {
libraries: {
libraries: {
'lib': lib.address
}
}
const factory = await ethers.getContractFactoryFromArtifact(artifact, options)
const storage = await factory.deploy();
await storage.deployed()
const storeValue = await storage.store(333);
// wait until the transaction is mined
await storeValue.wait();
console.log((await storage.getFromLib()).toString())
// expect((await storage.getFromLib()).toString()).to.equal('34');
} catch (e) {
console.error(e.message)
}

@ -483,6 +483,9 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
isValidProxyUpgrade={isValidProxyUpgrade}
modal={props.modal}
disabled={props.selectedAccount === ''}
solcVersion={props.solCompilerVersion}
setSolcVersion={props.setCompilerVersion}
getVersion={props.getCompilerVersion}
/>
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input

@ -32,7 +32,6 @@ export function ContractGUI(props: ContractGUIProps) {
const initializeFields = useRef<Array<HTMLInputElement | null>>([])
const basicInputRef = useRef<HTMLInputElement>()
const intl = useIntl()
useEffect(() => {
if (props.deployOption && Array.isArray(props.deployOption)) {
if (props.deployOption[0] && props.deployOption[0].title === 'Deploy with Proxy' && props.deployOption[0].active) handleDeployProxySelect(true)
@ -173,6 +172,7 @@ export function ContractGUI(props: ContractGUIProps) {
}
const handleActionClick = async () => {
props.getVersion()
if (deployState.deploy) {
const proxyInitializeString = getMultiValsString(initializeFields.current)
props.clickCallBack(props.initializerOptions.inputs.inputs, proxyInitializeString, ['Deploy with Proxy'])
@ -299,8 +299,8 @@ export function ContractGUI(props: ContractGUIProps) {
<div className="d-flex p-0 wrapperElement" onClick={handleActionClick} data-id={buttonOptions.dataId} data-title={buttonOptions.title}>
<button
className={`udapp_instanceButton text-nowrap overflow-hidden text-truncate ${props.widthClass} btn btn-sm ${buttonOptions.classList}`}
data-id={buttonOptions.dataId}
data-title={buttonOptions.title}
data-id={`${buttonOptions.dataId}`}
data-title={`${buttonOptions.title}`}
disabled={(toggleUpgradeImp && !proxyAddress) || props.disabled || (props.inputs !== '' && basicInput === '')}
>
{title}

@ -44,6 +44,8 @@ export function InstanceContainerUI(props: InstanceContainerProps) {
plugin={props.plugin}
exEnvironment={props.exEnvironment}
editInstance={props.editInstance}
solcVersion={props.solcVersion}
getVersion={props.getVersion}
/>
)
})}
@ -92,6 +94,8 @@ export function InstanceContainerUI(props: InstanceContainerProps) {
plugin={props.plugin}
exEnvironment={props.exEnvironment}
editInstance={props.editInstance}
solcVersion={props.solcVersion}
getVersion={props.getVersion}
/>
)
})}

@ -28,8 +28,6 @@ export function UniversalDappUI(props: UdappProps) {
const [evmBC, setEvmBC] = useState(null)
const [instanceBalance, setInstanceBalance] = useState(0)
const getVersion = () => window.location.href.split('=')[5].split('+')[0].split('-')[1]
useEffect(() => {
if (!props.instance.abi) {
const abi = txHelper.sortAbiFunction(props.instance.contractData.abi)
@ -438,6 +436,7 @@ export function UniversalDappUI(props: UdappProps) {
return (
<div key={index}>
<ContractGUI
getVersion={props.getVersion}
funcABI={funcABI}
clickCallBack={(valArray: {name: string; type: string}[], inputsValues: string) => {
runTransaction(lookupOnly, funcABI, valArray, inputsValues, index)
@ -472,10 +471,21 @@ export function UniversalDappUI(props: UdappProps) {
<div className="py-2 border-top d-flex justify-content-start flex-grow-1">
<FormattedMessage id="udapp.lowLevelInteractions" />
</div>
<CustomTooltip placement={'bottom-end'} tooltipClasses="text-wrap" tooltipId="receiveEthDocstoolTip" tooltipText={<FormattedMessage id="udapp.tooltipText8" />}>
<a href={`https://solidity.readthedocs.io/en/${getVersion()}/contracts.html#receive-ether-function`} target="_blank" rel="noreferrer">
<i aria-hidden="true" className="fas fa-info my-2 mr-1"></i>
</a>
<CustomTooltip
placement={'bottom-end'}
tooltipClasses="text-wrap"
tooltipId="receiveEthDocstoolTip"
tooltipText={<FormattedMessage id="udapp.tooltipText8" />}
>
{ // receive method added to solidity v0.6.x. use this as diff.
props.solcVersion.canReceive === false ? (
<a href={`https://solidity.readthedocs.io/en/v${props.solcVersion.version}/contracts.html`} target="_blank" rel="noreferrer">
<i aria-hidden="true" className="fas fa-info my-2 mr-1"></i>
</a>
) :<a href={`https://solidity.readthedocs.io/en/v${props.solcVersion.version}/contracts.html#receive-ether-function`} target="_blank" rel="noreferrer">
<i aria-hidden="true" className="fas fa-info my-2 mr-1"></i>
</a>
}
</CustomTooltip>
</div>
<div className="d-flex flex-column align-items-start">

@ -80,6 +80,22 @@ export function RunTabUI(props: RunTabProps) {
const [runTab, dispatch] = useReducer(runTabReducer, initialState)
const REACT_API = { runTab }
const currentfile = plugin.config.get('currentFile')
const [solcVersion, setSolcVersion] = useState<{version: string, canReceive: boolean}>({ version: '', canReceive: true })
const getVersion = () => {
let version = '0.8.25'
try {
version = window.location.href.split('=')[5].split('+')[0].split('-')[1].slice(1) ?? '0.8.25'
if (parseFloat(version) < 0.6) {
setSolcVersion({ version: version, canReceive: false })
} else {
setSolcVersion({ version: version, canReceive: true })
}
} catch (e) {
setSolcVersion({ version, canReceive: true })
console.log(e)
}
}
useEffect(() => {
if (!props.initialState) {
@ -306,6 +322,9 @@ export function RunTabUI(props: RunTabProps) {
isValidProxyAddress={isValidProxyAddress}
isValidProxyUpgrade={isValidProxyUpgrade}
proxy={runTab.proxy}
solCompilerVersion={solcVersion}
setCompilerVersion={setSolcVersion}
getCompilerVersion={getVersion}
/>
<RecorderUI
plugin={plugin}
@ -330,6 +349,8 @@ export function RunTabUI(props: RunTabProps) {
mainnetPrompt={mainnetPrompt}
runTransactions={executeTransactions}
sendValue={runTab.sendValue}
solcVersion={solcVersion}
getVersion={getVersion}
getFuncABIInputs={getFuncABIValues}
exEnvironment={runTab.selectExEnv}
editInstance={(instance) => {

@ -279,6 +279,11 @@ export interface ContractDropdownProps {
isValidProxyAddress?: (address: string) => Promise<boolean>,
isValidProxyUpgrade?: (proxyAddress: string, contractName: string, solcInput: SolcInput, solcOuput: SolcOutput, solcVersion: string) => Promise<LayoutCompatibilityReport | { ok: boolean, pass: boolean, warning: boolean }>,
proxy: { deployments: { address: string, date: string, contractName: string }[] }
solCompilerVersion: { version: string, canReceive: boolean }
setCompilerVersion: React.Dispatch<React.SetStateAction<{
version: string;
canReceive: boolean;}>>
getCompilerVersion: () => void
}
export interface RecorderProps {
@ -343,6 +348,8 @@ export interface InstanceContainerProps {
exEnvironment: string
editInstance: (instance) => void
plugin: RunTab
solcVersion: { version: string, canReceive: boolean }
getVersion: any
}
export interface Modal {
@ -397,6 +404,11 @@ export interface ContractGUIProps {
isValidProxyAddress?: (address: string) => Promise<boolean>,
isValidProxyUpgrade?: (proxyAddress: string) => Promise<LayoutCompatibilityReport | { ok: boolean, pass: boolean, warning: boolean }>,
modal?: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void, okBtnClass?: string, cancelBtnClass?: string) => void
solcVersion?: { version: string, canReceive: boolean }
setSolcVersion?: React.Dispatch<React.SetStateAction<{
version: string;
canReceive: boolean;}>>
getVersion: () => void
}
export interface MainnetProps {
network: Network,
@ -452,6 +464,8 @@ export interface UdappProps {
exEnvironment: string
editInstance: (instance) => void
plugin: RunTab
solcVersion: { version: string, canReceive: boolean }
getVersion: () => string
}
export interface DeployButtonProps {

Loading…
Cancel
Save