|
|
@ -1,13 +1,21 @@ |
|
|
|
import { EventEmitter } from 'events' |
|
|
|
import * as packageJson from '../../../package.json' |
|
|
|
import { Compiler } from 'remix-solidity' |
|
|
|
import { Plugin } from '@remixproject/engine' |
|
|
|
import { canUseWorker, urlFromVersion } from './compiler-utils' |
|
|
|
import { urlFromVersion } from './compiler-utils' |
|
|
|
import CompilerAbstract from './compiler-abstract' |
|
|
|
import { compile } from './compiler-helpers' |
|
|
|
|
|
|
|
import globalRegistry from '../../global/registry' |
|
|
|
|
|
|
|
|
|
|
|
import remixLib from 'remix-lib' |
|
|
|
import remixLib from 'remix-lib' |
|
|
|
|
|
|
|
|
|
|
|
class FetchAndCompile { |
|
|
|
const profile = { |
|
|
|
|
|
|
|
name: 'fetchAndCompile', |
|
|
|
|
|
|
|
methods: ['resolve'], |
|
|
|
|
|
|
|
version: packageJson.version |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default class FetchAndCompile extends Plugin { |
|
|
|
|
|
|
|
|
|
|
|
constructor () { |
|
|
|
constructor () { |
|
|
|
this.event = new EventEmitter() |
|
|
|
super(profile) |
|
|
|
this.compiler = null |
|
|
|
this.compiler = null |
|
|
|
this.unresolvedAddresses = [] |
|
|
|
this.unresolvedAddresses = [] |
|
|
|
this.firstResolvedAddress = null |
|
|
|
this.firstResolvedAddress = null |
|
|
@ -16,17 +24,20 @@ class FetchAndCompile { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Fetch compiliation metadata from source-Verify from a given @arg contractAddress - https://github.com/ethereum/source-verify
|
|
|
|
* Fetch compiliation metadata from source-Verify from a given @arg contractAddress - https://github.com/ethereum/source-verify
|
|
|
|
* Compile the code using Solidity compiler. |
|
|
|
* Put the artifacts in the file explorer |
|
|
|
|
|
|
|
* Compile the code using Solidity compiler |
|
|
|
|
|
|
|
* Returns compilation data |
|
|
|
* if no contract address are passed, we default to the first resolved address. |
|
|
|
* if no contract address are passed, we default to the first resolved address. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param {string} contractAddress - Address of the contrac to resolve |
|
|
|
* @param {string} contractAddress - Address of the contrac to resolve |
|
|
|
* @param {string} compilersartefacts - Object containing a mapping of compilation results (byContractAddress and __last) |
|
|
|
* @param {string} compilersartefacts - Object containing a mapping of compilation results (byContractAddress and __last) |
|
|
|
* @param {object} pluginAccess - any registered plugin (for making the calls) |
|
|
|
|
|
|
|
* @return {CompilerAbstract} - compilation data targeting the given @arg contractAddress |
|
|
|
* @return {CompilerAbstract} - compilation data targeting the given @arg contractAddress |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
async resolve (contractAddress, compilersartefacts, pluginAccess, targetPath, web3) { |
|
|
|
async resolve (contractAddress, targetPath, web3) { |
|
|
|
contractAddress = contractAddress || this.firstResolvedAddress |
|
|
|
contractAddress = contractAddress || this.firstResolvedAddress |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const compilersartefacts = globalRegistry.get('compilersartefacts').api |
|
|
|
|
|
|
|
|
|
|
|
const localCompilation = () => compilersartefacts.get('__last') ? compilersartefacts.get('__last') : null |
|
|
|
const localCompilation = () => compilersartefacts.get('__last') ? compilersartefacts.get('__last') : null |
|
|
|
|
|
|
|
|
|
|
|
const resolved = compilersartefacts.get(contractAddress) |
|
|
|
const resolved = compilersartefacts.get(contractAddress) |
|
|
@ -39,7 +50,7 @@ class FetchAndCompile { |
|
|
|
|
|
|
|
|
|
|
|
let network |
|
|
|
let network |
|
|
|
try { |
|
|
|
try { |
|
|
|
network = await pluginAccess.call('network', 'detectNetwork') |
|
|
|
network = await this.call('network', 'detectNetwork') |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
return localCompilation() |
|
|
|
return localCompilation() |
|
|
|
} |
|
|
|
} |
|
|
@ -58,38 +69,39 @@ class FetchAndCompile { |
|
|
|
if (found) { |
|
|
|
if (found) { |
|
|
|
compilersartefacts.addResolvedContract(contractAddress, compilation) |
|
|
|
compilersartefacts.addResolvedContract(contractAddress, compilation) |
|
|
|
this.firstResolvedAddress = contractAddress |
|
|
|
this.firstResolvedAddress = contractAddress |
|
|
|
setTimeout(_ => this.event.emit('usingLocalCompilation', contractAddress), 0) |
|
|
|
setTimeout(_ => this.emit('usingLocalCompilation', contractAddress), 0) |
|
|
|
return compilation |
|
|
|
return compilation |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let name = network.name.toLowerCase() |
|
|
|
let name = network.name.toLowerCase() |
|
|
|
name === 'main' ? 'mainnet' : name // source-verifier api expect "mainnet" and not "main"
|
|
|
|
name === 'main' ? 'mainnet' : name // source-verifier api expect "mainnet" and not "main"
|
|
|
|
await pluginAccess.call('manager', 'activatePlugin', 'source-verification') |
|
|
|
await this.call('manager', 'activatePlugin', 'source-verification') |
|
|
|
const data = await pluginAccess.call('source-verification', 'fetch', contractAddress, name.toLowerCase()) |
|
|
|
const data = await this.call('source-verification', 'fetch', contractAddress, name.toLowerCase()) |
|
|
|
if (!data || !data.metadata) { |
|
|
|
if (!data || !data.metadata) { |
|
|
|
setTimeout(_ => this.event.emit('notFound', contractAddress), 0) |
|
|
|
setTimeout(_ => this.emit('notFound', contractAddress), 0) |
|
|
|
this.unresolvedAddresses.push(contractAddress) |
|
|
|
this.unresolvedAddresses.push(contractAddress) |
|
|
|
return localCompilation() |
|
|
|
return localCompilation() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// set the solidity contract code using metadata
|
|
|
|
// set the solidity contract code using metadata
|
|
|
|
await pluginAccess.call('fileManager', 'setFile', `${targetPath}/${contractAddress}/metadata.json`, JSON.stringify(data.metadata, null, '\t')) |
|
|
|
await this.call('fileManager', 'setFile', `${targetPath}/${contractAddress}/metadata.json`, JSON.stringify(data.metadata, null, '\t')) |
|
|
|
let compilationTargets = {} |
|
|
|
let compilationTargets = {} |
|
|
|
for (let file in data.metadata.sources) { |
|
|
|
for (let file in data.metadata.sources) { |
|
|
|
const urls = data.metadata.sources[file].urls |
|
|
|
const urls = data.metadata.sources[file].urls |
|
|
|
for (let url of urls) { |
|
|
|
for (let url of urls) { |
|
|
|
if (url.includes('ipfs')) { |
|
|
|
if (url.includes('ipfs')) { |
|
|
|
let stdUrl = `ipfs://${url.split('/')[2]}` |
|
|
|
let stdUrl = `ipfs://${url.split('/')[2]}` |
|
|
|
const source = await pluginAccess.call('contentImport', 'resolve', stdUrl) |
|
|
|
const source = await this.call('contentImport', 'resolve', stdUrl) |
|
|
|
file = file.replace('browser/', '') // should be fixed in the remix IDE end.
|
|
|
|
file = file.replace('browser/', '') // should be fixed in the remix IDE end.
|
|
|
|
const path = `${targetPath}/${contractAddress}/${file}` |
|
|
|
const path = `${targetPath}/${contractAddress}/${file}` |
|
|
|
await pluginAccess.call('fileManager', 'setFile', path, source.content) |
|
|
|
await this.call('fileManager', 'setFile', path, source.content) |
|
|
|
compilationTargets[path] = { content: source.content } |
|
|
|
compilationTargets[path] = { content: source.content } |
|
|
|
break |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// compile
|
|
|
|
// compile
|
|
|
|
const settings = { |
|
|
|
const settings = { |
|
|
|
version: data.metadata.compiler.version, |
|
|
|
version: data.metadata.compiler.version, |
|
|
@ -98,32 +110,16 @@ class FetchAndCompile { |
|
|
|
optimize: data.metadata.settings.optimizer.enabled, |
|
|
|
optimize: data.metadata.settings.optimizer.enabled, |
|
|
|
compilerUrl: urlFromVersion(data.metadata.compiler.version) |
|
|
|
compilerUrl: urlFromVersion(data.metadata.compiler.version) |
|
|
|
} |
|
|
|
} |
|
|
|
return await (() => { |
|
|
|
try { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
setTimeout(_ => this.emit('compiling', settings), 0) |
|
|
|
setTimeout(_ => this.event.emit('compiling', settings), 0) |
|
|
|
const compData = await compile(compilationTargets, settings) |
|
|
|
if (!this.compiler) this.compiler = new Compiler(() => {}) |
|
|
|
compilersartefacts.addResolvedContract(contractAddress, compData) |
|
|
|
this.compiler.set('evmVersion', settings.evmVersion) |
|
|
|
this.firstResolvedAddress = contractAddress |
|
|
|
this.compiler.set('optimize', settings.optimize) |
|
|
|
return compData |
|
|
|
this.compiler.loadVersion(canUseWorker(settings.version), settings.compilerUrl) |
|
|
|
} catch (e) { |
|
|
|
this.compiler.event.register('compilationFinished', (success, compilationData, source) => { |
|
|
|
this.unresolvedAddresses.push(contractAddress) |
|
|
|
if (!success) { |
|
|
|
setTimeout(_ => this.emit('compilationFailed'), 0) |
|
|
|
this.unresolvedAddresses.push(contractAddress) |
|
|
|
return localCompilation() |
|
|
|
setTimeout(_ => this.event.emit('compilationFailed', compilationData), 0) |
|
|
|
} |
|
|
|
return resolve(null) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const compilerData = new CompilerAbstract(settings.version, compilationData, source) |
|
|
|
|
|
|
|
compilersartefacts.addResolvedContract(contractAddress, compilerData) |
|
|
|
|
|
|
|
this.firstResolvedAddress = contractAddress |
|
|
|
|
|
|
|
resolve(compilerData) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
this.compiler.event.register('compilerLoaded', (version) => { |
|
|
|
|
|
|
|
this.compiler.compile(compilationTargets, '') |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
})() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const fetchAndCompile = new FetchAndCompile() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default fetchAndCompile |
|
|
|
|
|
|
|