Skip to content

Commit 6cbf72a

Browse files
committed
refactor vyper to work with context command.
1 parent 11e26cd commit 6cbf72a

File tree

6 files changed

+186
-116
lines changed

6 files changed

+186
-116
lines changed

apps/vyper/src/app/app.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ interface OutputMap {
2828

2929
const App = () => {
3030
const [contract, setContract] = useState<string>()
31-
const [output, setOutput] = useState<any>({})
31+
const [output, setOutput] = useState<any>(remixClient.compilerOutput)
3232
const [state, setState] = useState<AppState>({
3333
status: 'idle',
3434
environment: 'remote',
@@ -53,6 +53,30 @@ const App = () => {
5353
start()
5454
}, [])
5555

56+
useEffect(() => {
57+
remixClient.eventEmitter.on('resetCompilerState', () => {
58+
resetCompilerResultState()
59+
})
60+
61+
return () => {
62+
remixClient.eventEmitter.off('resetCompilerState', () => {
63+
resetCompilerResultState()
64+
})
65+
}
66+
}, [])
67+
68+
useEffect(() => {
69+
remixClient.eventEmitter.on('setOutput', (payload) => {
70+
setOutput(payload)
71+
})
72+
73+
return () => {
74+
remixClient.eventEmitter.off('setOutput', (payload) => {
75+
setOutput(payload)
76+
})
77+
}
78+
}, [])
79+
5680
/** Update the environment state value */
5781
function setEnvironment(environment: 'local' | 'remote') {
5882
setState({...state, environment})
@@ -67,7 +91,7 @@ const App = () => {
6791
}
6892

6993
function resetCompilerResultState() {
70-
setOutput({})
94+
setOutput(remixClient.compilerOutput)
7195
}
7296

7397
return (

apps/vyper/src/app/components/CompilerButton.tsx

Lines changed: 6 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { Fragment, useState } from 'react'
2-
import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath} from '../utils'
2+
import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract} from '../utils'
33
import Button from 'react-bootstrap/Button'
4-
import _ from 'lodash'
54

65
interface Props {
76
compilerUrl: string
@@ -21,112 +20,14 @@ function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}:
2120
}
2221

2322
/** Compile a Contract */
24-
async function compileContract() {
25-
resetCompilerState()
26-
setLoadingSpinnerState(true)
27-
try {
28-
// await remixClient.discardHighlight()
29-
let _contract: any
30-
try {
31-
_contract = await remixClient.getContract()
32-
} catch (e: any) {
33-
setOutput('', {status: 'failed', message: e.message})
34-
return
35-
}
36-
remixClient.changeStatus({
37-
key: 'loading',
38-
type: 'info',
39-
title: 'Compiling'
40-
})
41-
let output
42-
try {
43-
output = await compile(compilerUrl, _contract)
44-
} catch (e: any) {
45-
remixClient.changeStatus({
46-
key: 'failed',
47-
type: 'error',
48-
title: e.message
49-
})
50-
return
51-
}
52-
const compileReturnType = () => {
53-
const t: any = toStandardOutput(contract, output)
54-
const temp = _.merge(t['contracts'][contract])
55-
const normal = normalizeContractPath(contract)[2]
56-
const abi = temp[normal]['abi']
57-
const evm = _.merge(temp[normal]['evm'])
58-
const dpb = evm.deployedBytecode
59-
const runtimeBytecode = evm.bytecode
60-
const methodIdentifiers = evm.methodIdentifiers
61-
62-
const result = {
63-
contractName: normal,
64-
abi: abi,
65-
bytecode: dpb,
66-
runtimeBytecode: runtimeBytecode,
67-
ir: '',
68-
methodIdentifiers: methodIdentifiers
69-
}
70-
return result
71-
}
72-
73-
// ERROR
74-
if (isCompilationError(output)) {
75-
const line = output.line
76-
if (line) {
77-
const lineColumnPos = {
78-
start: {line: line - 1, column: 10},
79-
end: {line: line - 1, column: 10}
80-
}
81-
// remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
82-
} else {
83-
const regex = output?.message?.match(/line ((\d+):(\d+))+/g)
84-
const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message
85-
if (regex) {
86-
let errorIndex = 0
87-
regex.map((errorLocation) => {
88-
const location = errorLocation?.replace('line ', '').split(':')
89-
let message = errors[errorIndex]
90-
errorIndex = errorIndex + 4
91-
if (message && message?.split('\n\n').length > 0) {
92-
try {
93-
message = message?.split('\n\n')[message.split('\n\n').length - 1]
94-
} catch (e) {}
95-
}
96-
if (location?.length > 0) {
97-
const lineColumnPos = {
98-
start: {line: parseInt(location[0]) - 1, column: 10},
99-
end: {line: parseInt(location[0]) - 1, column: 10}
100-
}
101-
// remixClient.highlight(lineColumnPos as any, _contract.name, message)
102-
}
103-
})
104-
}
105-
}
106-
throw new Error(output.message)
107-
}
108-
// SUCCESS
109-
// remixClient.discardHighlight()
110-
remixClient.changeStatus({
111-
key: 'succeed',
112-
type: 'success',
113-
title: 'success'
114-
})
115-
const data = toStandardOutput(_contract.name, output)
116-
remixClient.compilationFinish(_contract.name, _contract.content, data)
117-
setOutput(_contract.name, compileReturnType())
118-
} catch (err: any) {
119-
remixClient.changeStatus({
120-
key: 'failed',
121-
type: 'error',
122-
title: err.message
123-
})
124-
}
125-
}
12623

12724
return (
12825
<Fragment>
129-
<button data-id="compile" onClick={compileContract} title={contract} className="btn btn-primary w-100 d-block btn-block text-break remixui_disabled mb-1 mt-3">
26+
<button data-id="compile"
27+
onClick={() => compileContract(contract, compilerUrl, setOutput)}
28+
title={contract}
29+
className="btn btn-primary w-100 d-block btn-block text-break remixui_disabled mb-1 mt-3"
30+
>
13031
<div className="d-flex align-items-center justify-content-center fa-1x">
13132
<span className="fas fa-sync fa-pulse mr-1" />
13233
<div className="text-truncate overflow-hidden text-nowrap">

apps/vyper/src/app/utils/compiler.tsx

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { ABIDescription} from '@remixproject/plugin-api'
22
import axios from 'axios'
3+
import { remixClient } from './remix-client'
4+
import _ from 'lodash'
5+
36

47
export interface Contract {
58
name: string
@@ -167,6 +170,130 @@ export function toStandardOutput(fileName: string, compilationResult: any): any
167170
}
168171
}
169172
}
173+
174+
175+
export async function compileContract(contract: string, compilerUrl: string, setOutput?: any) {
176+
remixClient.eventEmitter.emit('resetCompilerState', {})
177+
178+
try {
179+
// await remixClient.discardHighlight()
180+
let _contract: any
181+
try {
182+
_contract = await remixClient.getContract()
183+
} catch (e: any) {
184+
if (setOutput === null || setOutput === undefined) {
185+
const compileResult = {
186+
status: 'failed',
187+
message: e.message
188+
}
189+
const compileResultKey = ''
190+
remixClient.eventEmitter.emit('setOutput', { compileResultKey, compileResult })
191+
} else {
192+
setOutput('', {status: 'failed', message: e.message})
193+
}
194+
return
195+
}
196+
remixClient.changeStatus({
197+
key: 'loading',
198+
type: 'info',
199+
title: 'Compiling'
200+
})
201+
let output
202+
try {
203+
output = await compile(compilerUrl, _contract)
204+
} catch (e: any) {
205+
remixClient.changeStatus({
206+
key: 'failed',
207+
type: 'error',
208+
title: e.message
209+
})
210+
return
211+
}
212+
const compileReturnType = () => {
213+
const t: any = toStandardOutput(contract, output)
214+
const temp = _.merge(t['contracts'][contract])
215+
const normal = normalizeContractPath(contract)[2]
216+
const abi = temp[normal]['abi']
217+
const evm = _.merge(temp[normal]['evm'])
218+
const dpb = evm.deployedBytecode
219+
const runtimeBytecode = evm.bytecode
220+
const methodIdentifiers = evm.methodIdentifiers
221+
222+
const result = {
223+
contractName: normal,
224+
abi: abi,
225+
bytecode: dpb,
226+
runtimeBytecode: runtimeBytecode,
227+
ir: '',
228+
methodIdentifiers: methodIdentifiers
229+
}
230+
return result
231+
}
232+
233+
// ERROR
234+
if (isCompilationError(output)) {
235+
const line = output.line
236+
if (line) {
237+
const lineColumnPos = {
238+
start: {line: line - 1, column: 10},
239+
end: {line: line - 1, column: 10}
240+
}
241+
// remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
242+
} else {
243+
const regex = output?.message?.match(/line ((\d+):(\d+))+/g)
244+
const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message
245+
if (regex) {
246+
let errorIndex = 0
247+
regex.map((errorLocation) => {
248+
const location = errorLocation?.replace('line ', '').split(':')
249+
let message = errors[errorIndex]
250+
errorIndex = errorIndex + 4
251+
if (message && message?.split('\n\n').length > 0) {
252+
try {
253+
message = message?.split('\n\n')[message.split('\n\n').length - 1]
254+
} catch (e) {}
255+
}
256+
if (location?.length > 0) {
257+
const lineColumnPos = {
258+
start: {line: parseInt(location[0]) - 1, column: 10},
259+
end: {line: parseInt(location[0]) - 1, column: 10}
260+
}
261+
// remixClient.highlight(lineColumnPos as any, _contract.name, message)
262+
}
263+
})
264+
}
265+
}
266+
throw new Error(output.message)
267+
}
268+
// SUCCESS
269+
// remixClient.discardHighlight()
270+
remixClient.changeStatus({
271+
key: 'succeed',
272+
type: 'success',
273+
title: 'success'
274+
})
275+
276+
const data = toStandardOutput(_contract.name, output)
277+
remixClient.compilationFinish(_contract.name, _contract.content, data)
278+
if (setOutput === null || setOutput === undefined) {
279+
const contractName = _contract['name']
280+
const compileResult = compileReturnType()
281+
remixClient.eventEmitter.emit('setOutput', { contractName, compileResult })
282+
} else {
283+
setOutput(_contract.name, compileReturnType())
284+
}
285+
} catch (err: any) {
286+
remixClient.changeStatus({
287+
key: 'failed',
288+
type: 'error',
289+
title: err.message
290+
})
291+
}
292+
}
293+
294+
295+
296+
170297
export type StandardOutput = {
171298
sources: {
172299
[fileName: string]: {

apps/vyper/src/app/utils/remix-client.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@ import {HighlightPosition, CompilationResult, RemixApi, customAction} from '@rem
22
import {Api, Status} from '@remixproject/plugin-utils'
33
import {createClient} from '@remixproject/plugin-webview'
44
import {PluginClient} from '@remixproject/plugin'
5-
import {Contract} from './compiler'
5+
import {Contract, compileContract} from './compiler'
66
import {ExampleContract} from '../components/VyperResult'
7+
import EventEmitter from 'events'
78

9+
10+
export type VyperComplierAddress = 'https://vyper2.remixproject.org/' | 'http://localhost:8000/'
811
export class RemixClient extends PluginClient {
912
private client = createClient<Api, Readonly<RemixApi>>(this)
13+
compilerUrl: VyperComplierAddress = 'https://vyper2.remixproject.org/'
14+
compilerOutput: any
15+
eventEmitter = new EventEmitter()
16+
17+
constructor() {
18+
super()
19+
this.compilerOutput = {}
20+
}
1021

1122
loaded() {
1223
return this.client.onload()
@@ -26,8 +37,16 @@ export class RemixClient extends PluginClient {
2637
})
2738
}
2839

40+
resetCompilerState() {
41+
this.compilerOutput = {}
42+
this.eventEmitter.emit('resetCompilerState', {})
43+
}
44+
2945
async vyperCompileCustomAction(action: customAction) {
30-
console.log('vyperCompileCustomAction', action)
46+
//read selected contract from file explorer and create contract type
47+
const contract = await this.getContract()
48+
//compile contract
49+
await compileContract(contract.name, this.compilerUrl)
3150
}
3251

3352
/** Load Ballot contract example into the file manager */

libs/remix-ui/vyper-compile-details/src/lib/vyper-compile-details.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ interface RemixUiVyperCompileDetailsProps {
1010
}
1111

1212
export function RemixUiVyperCompileDetails({ payload, theme, themeStyle }: RemixUiVyperCompileDetailsProps) {
13-
const dpayload = Object.values(payload) as any ?? {}
14-
const bcode = dpayload[0].bytecode ? dpayload[0].bytecode.object : ''
15-
const runtimeBcode = dpayload[0].runtimeBytecode ? dpayload[0].runtimeBytecode.object : ''
16-
const ir = dpayload[0].ir
17-
const methodIdentifiers= dpayload[0].methodIdentifiers
18-
const abi= dpayload[0].abi
13+
const compileResult = payload['compileResult'] ?? {}
14+
const bcode = compileResult.bytecode ? compileResult.bytecode.object : ''
15+
const runtimeBcode = compileResult.runtimeBytecode ? compileResult.runtimeBytecode.object : ''
16+
const ir = compileResult.ir
17+
const methodIdentifiers= compileResult.methodIdentifiers
18+
const abi= compileResult.abi
1919
return (
2020
<>
2121
<VyperCompile

libs/remix-ui/vyper-compile-details/src/lib/vyperCompile.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export interface VyperCompileProps {
2525
}
2626

2727
export default function VyperCompile({result, theme, themeStyle}: VyperCompileProps) {
28-
2928
const [active, setActive] = useState<keyof VyperCompilationResult>('abi')
3029
const tabContent = [
3130
{

0 commit comments

Comments
 (0)