Merge branch 'desktope2e-remixai' of https://github.com/ethereum/remix-project into desktope2e-remixai

pull/5100/head
STetsing 2 months ago
commit 66513f9212
  1. 109
      apps/remix-ide-e2e/src/tests/vyper_api.test.ts
  2. 4
      apps/vyper/src/app/components/CompilerButton.tsx
  3. 80
      apps/vyper/src/app/utils/compiler.tsx
  4. 24
      apps/vyper/src/app/utils/remix-client.tsx

@ -27,7 +27,7 @@ module.exports = {
.frameParent()
.clickLaunchIcon('filePanel')
.waitForElementVisible({
selector: "//*[@data-id='workspacesSelect' and contains(.,'snekmate')]",
selector: "//*[@data-id='workspacesSelect' and contains(.,'vyper')]",
locateStrategy: 'xpath',
timeout: 120000
})
@ -36,37 +36,38 @@ module.exports = {
locateStrategy: 'xpath',
timeout: 120000
})
.openFile('examples')
.openFile('examples/auctions')
.openFile('examples/auctions/blind_auction.vy')
},
// 'Add vyper file to run tests #group1': function (browser: NightwatchBrowser) {
// browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol'])
// '@sources': () => sources,
// 'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) {
// browser
// // .click('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
// // .rightClick('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
// // .waitForElementPresent('[data-id="contextMenuItemvyper"]')
// // .click('[data-id="contextMenuItemvyper"]')
// .clickLaunchIcon('vyper')
// // @ts-ignore
// .frame(0)
// .waitForElementVisible({
// selector:'[data-id="compilation-details"]',
// timeout: 120000
// })
// .click('[data-id="compilation-details"]')
// .frameParent()
// .waitForElementVisible('[data-id="copy-abi"]')
// .waitForElementVisible({
// selector: "//*[@class='variable-value' and contains(.,'highestBidder')]",
// locateStrategy: 'xpath',
// })
// },
'@sources': () => sources,
'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) {
browser
.addFileSnekmate('blind_auction.vy', sources[0]['blindAuction'])
.click('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
.rightClick('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
.waitForElementPresent('[data-id="contextMenuItemvyper"]')
.click('[data-id="contextMenuItemvyper"]')
.clickLaunchIcon('vyper')
// @ts-ignore
.frame(0)
.waitForElementVisible({
selector:'[data-id="compilation-details"]',
timeout: 120000
})
.click('[data-id="compilation-details"]')
.frameParent()
.waitForElementVisible('[data-id="copy-abi"]')
.waitForElementVisible({
selector: "//*[@class='variable-value' and contains(.,'highestBidder')]",
locateStrategy: 'xpath',
})
},
'Compile blind_auction should success #group1': function (browser: NightwatchBrowser) {
browser
// @ts-ignore
.clickLaunchIcon('vyper')
.frame(0)
.click('[data-id="compile"]')
.waitForElementVisible({
@ -145,32 +146,32 @@ module.exports = {
})
},
'Compile Ownable contract from snekmate #group1': function (browser: NightwatchBrowser) {
let contractAddress
browser
.frameParent()
.clickLaunchIcon('filePanel')
.switchWorkspace('snekmate')
.openFile('src')
.openFile('src/snekmate')
.openFile('src/snekmate/auth')
.openFile('src/snekmate/auth/Ownable.vy')
.rightClick('*[data-id="treeViewLitreeViewItemsrc/snekmate/auth/Ownable.vy"]')
.waitForElementVisible('*[data-id="contextMenuItemvyper"]')
.click('*[data-id="contextMenuItemvyper"]')
.clickLaunchIcon('vyper')
// @ts-ignore
.frame(0)
.click('[data-id="compile"]')
.waitForElementVisible({
selector:'[data-id="compilation-details"]',
timeout: 60000
})
.click('[data-id="compilation-details"]')
.frameParent()
.waitForElementVisible('[data-id="copy-abi"]')
.end()
}
// 'Compile Ownable contract from snekmate #group1': function (browser: NightwatchBrowser) {
// let contractAddress
// browser
// .frameParent()
// .clickLaunchIcon('filePanel')
// .switchWorkspace('vyper')
// .openFile('src')
// .openFile('src/snekmate')
// .openFile('src/snekmate/auth')
// .openFile('src/snekmate/auth/Ownable.vy')
// .rightClick('*[data-id="treeViewLitreeViewItemsrc/snekmate/auth/Ownable.vy"]')
// .waitForElementVisible('*[data-id="contextMenuItemvyper"]')
// .click('*[data-id="contextMenuItemvyper"]')
// .clickLaunchIcon('vyper')
// // @ts-ignore
// .frame(0)
// .click('[data-id="compile"]')
// .waitForElementVisible({
// selector:'[data-id="compilation-details"]',
// timeout: 60000
// })
// .click('[data-id="compilation-details"]')
// .frameParent()
// .waitForElementVisible('[data-id="copy-abi"]')
// .end()
// }
}
const testContract = `
@ -209,7 +210,7 @@ const sources = [{
'blindAuction' : { content: `
# Blind Auction. Adapted to Vyper from [Solidity by Example](https://github.com/ethereum/solidity/blob/develop/docs/solidity-by-example.rst#blind-auction-1)
#pragma version ^0.3.10
#pragma version >0.3.10
struct Bid:
blindedBid: bytes32
@ -384,6 +385,6 @@ def auctionEnd():
# Transfer funds to beneficiary
send(self.beneficiary, self.highestBid)
`}
` }
}
]

@ -1,5 +1,5 @@
import React, { Fragment, useEffect, useState } from 'react'
import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract, RemixClient} from '../utils'
import { isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract, RemixClient } from '../utils'
import Button from 'react-bootstrap/Button'
interface Props {
@ -11,7 +11,7 @@ interface Props {
remixClient: RemixClient
}
function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState, output, remixClient}: Props) {
function CompilerButton({ contract, setOutput, compilerUrl, resetCompilerState, output, remixClient }: Props) {
const [loadingSpinner, setLoadingSpinnerState] = useState(false)
if (!contract || !contract) {

@ -45,22 +45,30 @@ export function normalizeContractPath(contractPath: string): string[] {
return [folders,resultingPath, filename]
}
function parseErrorString(errorString) {
function parseErrorString(errorStructure: string[]) {
// Split the string into lines
let lines = errorString.trim().split('\n')
// Extract the line number and message
let message = errorString.trim()
let targetLine = lines[2].split(',')
let tline = lines[2].trim().split(' ')[1].split(':')
let errorType = ''
let message = ''
let tline = ''
errorStructure.forEach(errorMsg => {
const choppedup = errorMsg.split(': ')
errorType = choppedup[0].trim().split('\n')[1]
message = choppedup[1]
// if (errorStructure.length > 2) {
// console.log(choppedup[2].split(',')[1])
// }
// console.log(choppedup)
})
let lines = errorStructure[0].trim().split('\n')
const errorObject = {
status: 'failed',
message: message,
column: tline[1],
line: tline[0]
message: `${errorType} - ${message}`,
column: '',
line: ''
}
message = null
targetLine = null
// targetLine = null
lines = null
tline = null
return errorObject
@ -109,10 +117,10 @@ const compileReturnType = (output, contract) => {
const normal = normalizeContractPath(contract)[2]
const abi = temp[normal]['abi']
const evm = _.merge(temp[normal]['evm'])
const dpb = evm.deployedBytecode
const depByteCode = evm.deployedBytecode
const runtimeBytecode = evm.bytecode
const methodIdentifiers = evm.methodIdentifiers
const version = output?.compilers[0]?.version ?? '0.3.10'
const version = output?.compilers[0]?.version ?? '0.4.0'
const optimized = output?.compilers[0]?.settings?.optimize ?? true
const evmVersion = ''
@ -129,7 +137,7 @@ const compileReturnType = (output, contract) => {
} = {
contractName: normal,
abi,
bytecode: dpb,
bytecode: depByteCode,
runtimeBytecode,
ir: '',
methodIdentifiers,
@ -140,26 +148,32 @@ const compileReturnType = (output, contract) => {
return result
}
const fixContractContent = (content: string) => {
if (content.length === 0) return
const pragmaFound = content.includes('#pragma version ^0.3.10')
const wrongpragmaFound = content.includes('# pragma version ^0.3.10')
const evmVerFound = content.includes('#pragma evm-version shanghai')
const pragma = '#pragma version ^0.3.10'
const evmVer = '#pragma evm-version shanghai'
if (evmVerFound === false) {
content = `${evmVer}\n${content}`
}
if (wrongpragmaFound === true) {
content = content.replace('# pragma version ^0.3.10', '')
const updatePragmaDeclaration = (content: string) => {
const pragmaRegex = /#\s*pragma\s+[@]*version\s+([~<>!=^]+)\s*(\d+\.\d+\.\d+)/
const oldPragmaRegex = /#\s*pragma\s+[@]*version\s+([\^^]+)\s*(\d+\.\d+\.\d+)/
const oldPragmaDeclaration = ['# pragma version ^0.2.16', '# pragma version ^0.3.10', '#pragma version ^0.2.16', '#pragma version ^0.3.10']
const pragmaFound = content.match(pragmaRegex)
const oldPragmaFound = content.match(oldPragmaRegex)
const pragma = '# pragma version ~=0.4.0'
if (oldPragmaFound) {
// oldPragmaDeclaration.forEach(declaration => {
// content = content.replace(declaration, '# pragma version >0.3.10')
// })
return content
}
if (pragmaFound === false ) {
content = `${pragma}\n${content}`
if (!pragmaFound) {
content = `${pragma}\n\n${content}`
}
return content
}
const fixContractContent = (content: string) => {
if (content.length === 0) return
return updatePragmaDeclaration(content)
}
/**
* Compile the a contract
* @param url The url of the compiler
@ -174,13 +188,16 @@ export async function compile(url: string, contract: Contract): Promise<any> {
throw new Error('Use extension .vy for Vyper.')
}
const cleanedUpContent = fixContractContent(contract.content)
let contractName = contract['name']
const compilePackage = {
manifest: 'ethpm/3',
sources: {
[contractName] : { content : fixContractContent(contract.content) }
[contractName] : { content : cleanedUpContent }
}
}
let response = await axios.post(`${url}compile`, compilePackage )
if (response.status === 404) {
@ -194,6 +211,7 @@ export async function compile(url: string, contract: Contract): Promise<any> {
contractName = null
response = null
let result: any
let intermediateError
const status = await (await axios.get(url + 'status/' + compileCode , {
method: 'Get'
@ -208,7 +226,9 @@ export async function compile(url: string, contract: Contract): Promise<any> {
const intermediate = await(await axios.get(url + 'exceptions/' + compileCode , {
method: 'Get'
})).data
result = parseErrorString(intermediate[0])
// console.log('Errors found', intermediate)
result = parseErrorString(intermediate)
intermediateError = intermediate
return result
}
await new Promise((resolve) => setTimeout(() => resolve({}), 3000))

@ -83,23 +83,23 @@ export class RemixClient extends PluginClient<any, CustomRemixApi> {
try {
// @ts-ignore
this.call('notification', 'toast', 'cloning Snekmate Vyper repository...')
this.call('notification', 'toast', 'cloning Snekmate Vyper repository...')
await this.call(
'dgitApi',
'clone',
{url: 'https://github.com/pcaversaccio/snekmate', token: null, branch: 'main', singleBranch: false, workspaceName: 'snekmate'},
{ url: 'https://github.com/vyperlang/vyper', token: null, branch: 'master', singleBranch: false, workspaceName: 'vyper' },
)
await this.call(
'dgitApi',
'checkout',
{
ref:'v0.0.5',
force: true,
refresh: true,
}
)
// await this.call(
// 'dgitApi',
// 'checkout',
// {
// ref:'v0.0.5',
// force: true,
// refresh: true,
// }
// )
this.call(
// @ts-ignore
'notification',

Loading…
Cancel
Save