Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vyper compiler updates #5178

Merged
merged 12 commits into from
Sep 19, 2024
109 changes: 55 additions & 54 deletions apps/remix-ide-e2e/src/tests/vyper_api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand All @@ -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({
Expand Down Expand Up @@ -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 = `
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -384,6 +385,6 @@ def auctionEnd():

# Transfer funds to beneficiary
send(self.beneficiary, self.highestBid)
`}
` }
}
]
4 changes: 2 additions & 2 deletions apps/vyper/src/app/components/CompilerButton.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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) {
Expand Down
80 changes: 50 additions & 30 deletions apps/vyper/src/app/utils/compiler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = ''

Expand All @@ -129,7 +137,7 @@ const compileReturnType = (output, contract) => {
} = {
contractName: normal,
abi,
bytecode: dpb,
bytecode: depByteCode,
runtimeBytecode,
ir: '',
methodIdentifiers,
Expand All @@ -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
Expand All @@ -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) {
Expand All @@ -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'
Expand All @@ -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))
Expand Down
24 changes: 12 additions & 12 deletions apps/vyper/src/app/utils/remix-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Loading