Merge branch 'master' of https://github.com/ethereum/remix-project into desktopmerge

desktopmerge
filip mertens 1 year ago
commit f4dec702ed
  1. 19
      apps/circuit-compiler/src/app/components/compileBtn.tsx
  2. 2
      apps/circuit-compiler/src/app/components/container.tsx
  3. 6
      apps/circuit-compiler/src/app/components/feedback.tsx
  4. 4
      apps/circuit-compiler/src/app/components/options.tsx
  5. 1
      apps/circuit-compiler/src/app/components/r1csBtn.tsx
  6. 6
      apps/circuit-compiler/src/app/components/witness.tsx
  7. 2
      apps/circuit-compiler/src/app/components/witnessToggler.tsx
  8. 18
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  9. 178
      apps/remix-ide-e2e/src/tests/circom.test.ts
  10. 2
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  11. 13
      apps/remix-ide/src/app/providers/abstract-provider.tsx
  12. 6
      apps/remix-ide/src/app/providers/injected-provider.tsx
  13. 2
      apps/remix-ide/src/app/tabs/web3-provider.js
  14. 18
      apps/remix-ide/src/blockchain/blockchain.tsx
  15. 3
      apps/remix-ide/src/blockchain/execution-context.js
  16. 52
      apps/walletconnect/src/services/WalletConnectRemixClient.ts
  17. 11
      libs/ghaction-helper/package.json
  18. 2
      libs/ghaction-helper/src/methods.ts
  19. 10
      libs/remix-analyzer/package.json
  20. 8
      libs/remix-astwalker/package.json
  21. 14
      libs/remix-debug/package.json
  22. 8
      libs/remix-lib/package.json
  23. 8
      libs/remix-lib/src/execution/txHelper.ts
  24. 24
      libs/remix-lib/src/execution/txRunnerWeb3.ts
  25. 2
      libs/remix-lib/src/hash.ts
  26. 9
      libs/remix-simulator/package.json
  27. 11
      libs/remix-simulator/src/methods/transactions.ts
  28. 2
      libs/remix-simulator/src/vm-context.ts
  29. 8
      libs/remix-solidity/package.json
  30. 12
      libs/remix-tests/package.json
  31. 8
      libs/remix-ui/home-tab/src/lib/components/homeTablangOptions.tsx
  32. 5
      libs/remix-ui/run-tab/src/lib/components/mainnet.tsx
  33. 2
      libs/remix-ui/solidity-compiler/src/lib/api/compiler-api.ts
  34. 4
      libs/remix-ui/terminal/src/lib/components/Context.tsx
  35. 4
      libs/remix-ui/terminal/src/lib/components/Table.tsx
  36. 4
      libs/remix-url-resolver/package.json
  37. 6
      libs/remix-ws-templates/package.json
  38. 2
      libs/remixd/package.json
  39. 4
      package.json

@ -9,20 +9,21 @@ export function CompileBtn () {
return (
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={
<div className="text-left">
<div>
<b>Ctrl+S</b> to compile {appState.filePath}
</div>
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={
<div className="text-left">
<div>
<b>Ctrl+S</b> to compile {appState.filePath}
</div>
}
>
</div>
}
>
<button
className="btn btn-primary btn-block d-block w-100 text-break mb-1 mt-3"
onClick={() => { compileCircuit(plugin, appState) }}
disabled={(appState.filePath === "") || (appState.status === "compiling") || (appState.status === "generating")}
data-id="compile_circuit_btn"
>
<div className="d-flex align-items-center justify-content-center">
<RenderIf condition={appState.status === 'compiling'}>

@ -70,7 +70,7 @@ export function Container () {
<WitnessSection plugin={circuitApp.plugin} signalInputs={circuitApp.appState.signalInputs} status={circuitApp.appState.status} />
</WitnessToggler>
</RenderIf>
<RenderIf condition={circuitApp.appState.status !== 'compiling' && circuitApp.appState.status !== 'computing' && circuitApp.appState.status !== 'generating'}>
<RenderIf condition={(circuitApp.appState.status !== 'compiling') && (circuitApp.appState.status !== 'computing') && (circuitApp.appState.status !== 'generating')}>
<CompilerFeedback feedback={circuitApp.appState.feedback} filePathToId={circuitApp.appState.filePathToId} openErrorLocation={handleOpenErrorLocation} hideWarnings={circuitApp.appState.hideWarnings} />
</RenderIf>
</div>

@ -21,7 +21,7 @@ export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openEr
<div>
<div className="circuit_errors_box py-4">
<RenderIf condition={ (typeof feedback === "string") && showException }>
<div className="circuit_feedback error alert alert-danger">
<div className="circuit_feedback error alert alert-danger" data-id="circuit_feedback">
<span> { feedback } </span>
<div className="close" data-id="renderer" onClick={handleCloseException}>
<i className="fas fa-times"></i>
@ -39,12 +39,12 @@ export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openEr
Array.isArray(feedback) && feedback.map((response, index) => (
<div key={index} onClick={() => handleOpenError(response)}>
<RenderIf condition={response.type === 'Error'}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-danger`}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-danger`} data-id="circuit_feedback">
<FeedbackAlert message={response.message} location={ response.labels[0] ? response.labels[0].message + ` ${filePathToId[response.labels[0].file_id]}:${response.labels[0].range.start}:${response.labels[0].range.end}` : null} />
</div>
</RenderIf>
<RenderIf condition={(response.type === 'Warning') && !hideWarnings}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-warning`}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-warning`} data-id="circuit_feedback">
<FeedbackAlert message={response.message} location={null} />
</div>
</RenderIf>

@ -14,7 +14,7 @@ export function CompileOptions ({autoCompile, hideWarnings, setCircuitAutoCompil
checked={autoCompile}
id="autoCompileCircuit"
/>
<label className="form-check-label custom-control-label" htmlFor="autoCompileCircuit">
<label className="form-check-label custom-control-label" htmlFor="autoCompileCircuit" data-id="auto_compile_circuit_checkbox_input">
<FormattedMessage id="circuit.autoCompile" />
</label>
</div>
@ -27,7 +27,7 @@ export function CompileOptions ({autoCompile, hideWarnings, setCircuitAutoCompil
title="Hide warnings"
checked={hideWarnings}
/>
<label className="form-check-label custom-control-label" htmlFor="hideCircuitWarnings">
<label className="form-check-label custom-control-label" htmlFor="hideCircuitWarnings" data-id="hide_circuit_warnings_checkbox_input">
<FormattedMessage id="solidity.hideWarnings" />
</label>
</div>

@ -12,6 +12,7 @@ export function R1CSBtn () {
className="btn btn-secondary btn-block d-block w-100 text-break mb-1 mt-2"
onClick={() => { generateR1cs(plugin, appState) }}
disabled={(appState.filePath === "") || (appState.status === "compiling") || (appState.status === "generating") || (appState.status === "computing")}
data-id="generate_r1cs_btn"
>
<CustomTooltip
placement="auto"

@ -26,14 +26,16 @@ export function WitnessSection ({ plugin, signalInputs, status }: {plugin: Circo
<label className="circuit_inner_label form-check-label" htmlFor="circuitPrimeSelector">
<FormattedMessage id="circuit.signalInput" /> { input }
</label>
<input className="form-control m-0 txinput" placeholder={input} name={input} onChange={handleSignalInput} />
<input className="form-control m-0 txinput" placeholder={input} name={input} onChange={handleSignalInput} data-id={`circuit_input_${input}`} />
</div>
))
}
<button
className="btn btn-sm btn-secondary"
onClick={() => { computeWitness(plugin, status, witnessValues) }}
disabled={(status === "compiling") || (status === "generating") || (status === "computing")}>
disabled={(status === "compiling") || (status === "generating") || (status === "computing")}
data-id="compute_witness_btn"
>
<RenderIf condition={status === 'computing'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>

@ -11,7 +11,7 @@ export function WitnessToggler ({ children }: { children: JSX.Element }) {
return (
<div>
<div className="d-flex circuit_config_section justify-content-between" onClick={toggleConfigurations}>
<div className="d-flex circuit_config_section justify-content-between" onClick={toggleConfigurations} data-id="witness_toggler">
<div className="d-flex">
<label className="mt-1 circuit_config_section">
<FormattedMessage id="circuit.computeWitness" />

@ -32,7 +32,7 @@ export class CircomPluginClient extends PluginClient {
this.internalEvents.emit('circom_activated')
}
async parse(path: string, fileContent?: string): Promise<CompilerReport[]> {
async parse(path: string, fileContent?: string): Promise<[CompilerReport[], Record<string, string>]> {
if (!fileContent) {
// @ts-ignore
fileContent = await this.call('fileManager', 'readFile', path)
@ -45,7 +45,7 @@ export class CircomPluginClient extends PluginClient {
try {
const result: CompilerReport[] = JSON.parse(parsedOutput.report())
const mapReportFilePathToId = {}
const mapReportFilePathToId: Record<string, string> = {}
if (result.length === 0) {
// @ts-ignore
@ -101,10 +101,8 @@ export class CircomPluginClient extends PluginClient {
await this.call('editor', 'clearErrorMarkers', [path])
}
}
this.internalEvents.emit('circuit_parsing_done', result, mapReportFilePathToId)
return result
return [result, mapReportFilePathToId]
} catch (e) {
throw new Error(e)
}
@ -112,7 +110,7 @@ export class CircomPluginClient extends PluginClient {
async compile(path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_compiling_start')
const parseErrors = await this.parse(path)
const [parseErrors, filePathToId] = await this.parse(path)
if (parseErrors && (parseErrors.length > 0)) {
if (parseErrors[0].type === 'Error') {
@ -121,6 +119,8 @@ export class CircomPluginClient extends PluginClient {
} else if (parseErrors[0].type === 'Warning') {
this.internalEvents.emit('circuit_parsing_warning', parseErrors)
}
} else {
this.internalEvents.emit('circuit_parsing_done', parseErrors, filePathToId)
}
if (compilationConfig) {
const { prime, version } = compilationConfig
@ -160,7 +160,7 @@ export class CircomPluginClient extends PluginClient {
async generateR1cs (path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_generating_r1cs_start')
const parseErrors = await this.parse(path)
const [parseErrors, filePathToId] = await this.parse(path)
if (parseErrors && (parseErrors.length > 0)) {
if (parseErrors[0].type === 'Error') {
@ -169,6 +169,8 @@ export class CircomPluginClient extends PluginClient {
} else if (parseErrors[0].type === 'Warning') {
this.internalEvents.emit('circuit_parsing_warning', parseErrors)
}
} else {
this.internalEvents.emit('circuit_parsing_done', parseErrors, filePathToId)
}
if (compilationConfig) {
const { prime, version } = compilationConfig

@ -0,0 +1,178 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'Should create semaphore workspace template #group1 #group2 #group3 #group4': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
.click('select[id="wstemplate"]')
.click('select[id="wstemplate"] option[value=semaphore]')
.waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
.execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/semaphore.circom"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/run_setup.ts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]')
},
'Should compile a simple circuit using editor play button #group1': function (browser: NightwatchBrowser) {
browser
.click('[data-id="treeViewLitreeViewItemcircuits/simple.circom"]')
.waitForElementPresent('[data-path="Semaphore - 1/circuits/simple.circom"]')
.waitForElementVisible('[data-path="Semaphore - 1/circuits/simple.circom"]')
.click('[data-id="play-editor"]')
.waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
},
'Should compute a witness for a simple circuit #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('circuit-compiler')
.frame(0)
.waitForElementVisible('[data-id="witness_toggler"]')
.click('[data-id="witness_toggler"]')
.waitForElementVisible('[data-id="compute_witness_btn"]')
.waitForElementVisible('[data-id="circuit_input_a"]')
.waitForElementVisible('[data-id="circuit_input_b"]')
.setValue('[data-id="circuit_input_a"]', '1')
.setValue('[data-id="circuit_input_b"]', '2')
.click('[data-id="compute_witness_btn"]')
.frameParent()
.clickLaunchIcon('filePanel')
.waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wtn"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wtn"]')
},
'Should compile a simple circuit using compile button in circom plugin #group2': function (browser: NightwatchBrowser) {
browser
.click('[data-id="treeViewLitreeViewItemcircuits/simple.circom"]')
.waitForElementPresent('[data-path="Semaphore - 1/circuits/simple.circom"]')
.waitForElementVisible('[data-path="Semaphore - 1/circuits/simple.circom"]')
.clickLaunchIcon('circuit-compiler')
.frame(0)
.waitForElementPresent('button[data-id="compile_circuit_btn"]')
.waitForElementVisible('button[data-id="compile_circuit_btn"]')
.click('button[data-id="compile_circuit_btn"]')
.frameParent()
.clickLaunchIcon('filePanel')
.waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
},
'Should generate R1CS for a simple circuit #group2': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('circuit-compiler')
.frame(0)
.waitForElementPresent('button[data-id="generate_r1cs_btn"]')
.waitForElementVisible('button[data-id="generate_r1cs_btn"]')
.click('button[data-id="generate_r1cs_btn"]')
.frameParent()
.clickLaunchIcon('filePanel')
.waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.r1cs"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.r1cs"]')
},
'Should compile a simple circuit using CTRL + S from the editor #group3': function (browser: NightwatchBrowser) {
browser
.click('[data-id="treeViewLitreeViewItemcircuits/simple.circom"]')
.waitForElementPresent('[data-path="Semaphore - 1/circuits/simple.circom"]')
.waitForElementVisible('[data-path="Semaphore - 1/circuits/simple.circom"]')
.perform(function () {
const actions = this.actions({async: true})
return actions.keyDown(this.Keys.CONTROL).sendKeys('s')
})
.waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
},
'Should display warnings for compiled circuit without pragma version #group4': function (browser: NightwatchBrowser) {
browser
.click('[data-id="treeViewLitreeViewItemcircuits/simple.circom"]')
.waitForElementPresent('[data-path="Semaphore - 1/circuits/simple.circom"]')
.waitForElementVisible('[data-path="Semaphore - 1/circuits/simple.circom"]')
.setEditorValue(warningCircuit)
.clickLaunchIcon('circuit-compiler')
.frame(0)
.waitForElementPresent('button[data-id="compile_circuit_btn"]')
.waitForElementVisible('button[data-id="compile_circuit_btn"]')
.click('button[data-id="compile_circuit_btn"]')
.waitForElementPresent('[data-id="circuit_feedback"]')
.waitForElementVisible('[data-id="circuit_feedback"]')
.assert.hasClass('[data-id="circuit_feedback"]', 'alert-warning')
.waitForElementContainsText('[data-id="circuit_feedback"]', 'File circuits/simple.circom does not include pragma version. Assuming pragma version (2, 1, 5)')
},
'Should hide/show warnings for compiled circuit #group4': function (browser: NightwatchBrowser) {
browser
.click('[data-id="hide_circuit_warnings_checkbox_input"]')
.waitForElementNotPresent('[data-id="circuit_feedback"]')
.click('[data-id="hide_circuit_warnings_checkbox_input"]')
.waitForElementVisible('[data-id="circuit_feedback"]')
.waitForElementContainsText('[data-id="circuit_feedback"]', 'File circuits/simple.circom does not include pragma version. Assuming pragma version (2, 1, 5)')
},
'Should display error for invalid circuit #group4': function (browser: NightwatchBrowser) {
browser
.frameParent()
.setEditorValue(errorCircuit)
.frame(0)
.waitForElementPresent('button[data-id="compile_circuit_btn"]')
.waitForElementVisible('button[data-id="compile_circuit_btn"]')
.click('button[data-id="compile_circuit_btn"]')
.waitForElementPresent('[data-id="circuit_feedback"]')
.assert.hasClass('[data-id="circuit_feedback"]', 'alert-danger')
.waitForElementContainsText('[data-id="circuit_feedback"]', 'No main specified in the project structure')
},
'Should auto compile circuit #group4': function (browser: NightwatchBrowser) {
browser
.click('[data-id="auto_compile_circuit_checkbox_input"]')
.frameParent()
.setEditorValue(validCircuit)
.frame(0)
.waitForElementNotPresent('[data-id="circuit_feedback"]')
.frameParent()
.clickLaunchIcon('filePanel')
.waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]')
}
}
const warningCircuit = `
template Multiplier2() {
signal input a;
signal input b;
signal output c;
c <== a*b;
}
component main = Multiplier2();
`
const errorCircuit = `
pragma circom 2.0.0;
template Multiplier2() {
signal input a;
signal input b;
signal output c;
c <== a*b;
}
`
const validCircuit = `
pragma circom 2.0.0;
template Multiplier2() {
signal input a;
signal input b;
signal output c;
c <== a*b;
}
component main = Multiplier2();
`

@ -132,7 +132,7 @@ module.exports = {
.click('*[data-id="testTabCheckAllTests"]')
.clickElementAtPosition('.singleTestLabel', 1)
.scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]')
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'revert Deploy Failed', 120000)
.waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', 'contract deployment failed: revert', 120000)
},
'Should fail when parameters are passed to method in test contract #group3': function (browser: NightwatchBrowser) {

@ -14,11 +14,15 @@ export type JsonDataResult = {
id: number
jsonrpc: string // version
result?: any
error?: any
error?: {
code: number,
message: string
data?: string
}
errorData?: any
}
export type RejectRequest = (error: Error) => void
export type RejectRequest = (error: JsonDataResult) => void
export type SuccessRequest = (data: JsonDataResult) => void
export interface IProvider {
@ -98,7 +102,7 @@ export abstract class AbstractProvider extends Plugin implements IProvider {
sendAsync(data: JsonDataRequest): Promise<JsonDataResult> {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
if (!this.provider) return reject(new Error('provider node set'))
if (!this.provider) return reject({jsonrpc: '2.0', id: data.id, error: { message: 'provider node set', code: -32603 } } as JsonDataResult)
this.sendAsyncInternal(data, resolve, reject)
})
}
@ -128,7 +132,8 @@ export abstract class AbstractProvider extends Plugin implements IProvider {
if (error && error.message && error.message.includes('net_version') && error.message.includes('SERVER_ERROR')) {
this.switchAway(true)
}
reject(error)
error.code = -32603
reject({jsonrpc: '2.0', error, id: data.id})
}
} else {
const result = data.method === 'net_listening' ? 'canceled' : []

@ -80,7 +80,7 @@ export abstract class InjectedProvider extends Plugin implements IProvider {
this.call('notification', 'toast', 'No injected provider (e.g Metamask) has been found.')
return resolve({
jsonrpc: '2.0',
error: 'no injected provider found',
error: { message: 'no injected provider found', code: -32603 },
id: data.id
})
}
@ -89,7 +89,7 @@ export abstract class InjectedProvider extends Plugin implements IProvider {
if (web3Provider.request) resultData = await web3Provider.request({method: data.method, params: data.params})
else if (web3Provider.send) resultData = await web3Provider.send(data.method, data.params)
else {
resolve({jsonrpc: '2.0', error: 'provider not valid', id: data.id})
resolve({jsonrpc: '2.0', error: { message: 'provider not valid', code: -32603 }, id: data.id})
return
}
if (resultData) {
@ -98,7 +98,7 @@ export abstract class InjectedProvider extends Plugin implements IProvider {
}
resolve({jsonrpc: '2.0', result: resultData, id: data.id})
} else {
resolve({jsonrpc: '2.0', error: 'no return data provided', id: data.id})
resolve({jsonrpc: '2.0', result: null, id: data.id})
}
} catch (error) {
if (error.data && error.data.originalError && error.data.originalError.data) {

@ -64,7 +64,7 @@ export class Web3ProviderModule extends Plugin {
try {
resultFn(null, await provider.sendAsync(payload))
} catch (e) {
resultFn(e.message)
resultFn(e.error ? new Error(e.error) : new Error(e))
}
} else {
reject(new Error('User denied permission'))

@ -940,12 +940,20 @@ export class Blockchain extends Plugin {
cb(null, txResult, address, returnValue)
} catch (error) {
if (this.isInjectedWeb3()) {
const errorMessage = error.innerError ? error.innerError.message : error.message
const errorData = error.innerError ? error.innerError.data : error.data
const buildError = async (errorMessage, errorData) => {
const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas')
const injectedError = txExecution.checkError({ errorMessage, errorData }, compiledContracts)
cb(injectedError.message)
return txExecution.checkError({ errorMessage, errorData }, compiledContracts)
}
let errorMessage
let errorData
if (error.innerError) {
errorMessage = error.innerError.message
errorData = error.innerError.data
cb((await buildError(errorMessage, errorData)).message)
} else if (error.message || error.data) {
errorMessage = error.message
errorData = error.data
cb((await buildError(errorMessage, errorData)).message)
} else
cb(error)
}

@ -7,12 +7,14 @@ const _paq = window._paq = window._paq || []
let web3
const config = { defaultTransactionType: '0x0' }
if (typeof window !== 'undefined' && typeof window.ethereum !== 'undefined') {
var injectedProvider = window.ethereum
web3 = new Web3(injectedProvider)
} else {
web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))
}
web3.eth.setConfig(config)
/*
trigger contextChanged, web3EndpointChanged
@ -59,6 +61,7 @@ export class ExecutionContext {
}
setWeb3 (context, web3) {
web3.setConfig(config)
this.customWeb3[context] = web3
}

@ -24,6 +24,7 @@ export class WalletConnectRemixClient extends PluginClient {
chains: Chain[]
currentChain: number
internalEvents: EventManager
currentAcount: string
constructor() {
super()
@ -59,7 +60,9 @@ export class WalletConnectRemixClient extends PluginClient {
]
const {publicClient} = configureChains(this.chains, [
w3mProvider({projectId: PROJECT_ID})
])
], {
pollingInterval: 5000
})
this.wagmiConfig = createConfig({
autoConnect: false,
@ -75,13 +78,17 @@ export class WalletConnectRemixClient extends PluginClient {
subscribeToEvents() {
this.wagmiConfig.subscribe((event) => {
if (event.status === 'connected') {
this.emit('accountsChanged', [event.data.account])
if (event.data.account !== this.currentAcount) {
this.currentAcount = event.data.account
this.emit('accountsChanged', [event.data.account])
}
if (this.currentChain !== event.data.chain.id) {
this.currentChain = event.data.chain.id
this.emit('chainChanged', event.data.chain.id)
}
} else if (event.status === 'disconnected') {
this.emit('accountsChanged', [])
this.currentAcount = ''
this.emit('chainChanged', 0)
this.currentChain = 0
}
@ -106,25 +113,44 @@ export class WalletConnectRemixClient extends PluginClient {
if (provider.isMetaMask) {
return new Promise((resolve) => {
provider.sendAsync(data, (err, response) => {
if (err) {
console.error(err)
return resolve({jsonrpc: '2.0', result: [], id: data.id})
provider.sendAsync(data, (error, response) => {
if (error) {
if (error.data && error.data.originalError && error.data.originalError.data) {
resolve({
jsonrpc: '2.0',
error: error.data.originalError,
id: data.id
})
} else if (error.data && error.data.message) {
resolve({
jsonrpc: '2.0',
error: error.data && error.data,
id: data.id
})
} else {
resolve({
jsonrpc: '2.0',
error,
id: data.id
})
}
}
return resolve(response)
})
})
} else {
const message = await provider.request(data)
return {jsonrpc: '2.0', result: message, id: data.id}
try {
const message = await provider.request(data)
return {jsonrpc: '2.0', result: message, id: data.id}
} catch (e) {
return {jsonrpc: '2.0', error: { message: e.message, code: -32603 }, id: data.id}
}
}
}
} else {
console.error(
`Cannot make ${data.method} request. Remix client is not connected to walletconnect client`
)
return {jsonrpc: '2.0', result: [], id: data.id}
const err = `Cannot make ${data.method} request. Remix client is not connected to walletconnect client`
console.error(err)
return {jsonrpc: '2.0', error: { message: err, code: -32603 }, id: data.id}
}
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/ghaction-helper",
"version": "0.1.13",
"version": "0.1.16",
"description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js",
"scripts": {
@ -19,18 +19,17 @@
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": {
"@remix-project/remix-solidity": "^0.5.19",
"@remix-project/remix-solidity": "^0.5.22",
"@types/chai": "^4.3.4",
"typescript": "^4.9.3"
},
"dependencies": {
"@ethereum-waffle/chai": "^3.4.4",
"@remix-project/remix-simulator": "^0.2.33",
"@remix-project/remix-simulator": "^0.2.36",
"chai": "^4.3.7",
"ethers": "^5.7.2",
"web3": "^4.1.1"
},
"types": "./src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220"
}
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1"
}

@ -11,12 +11,14 @@ const providerConfig = {
blockNumber: global.blockNumber || null
}
const config = { defaultTransactionType: '0x0' }
global.remixProvider = new Provider(providerConfig)
global.remixProvider.init()
global.web3Provider = new ethers.providers.Web3Provider(global.remixProvider)
global.provider = global.web3Provider
global.ethereum = global.web3Provider
global.web3 = new Web3(global.web3Provider)
global.web3.eth.setConfig(config)
const isFactoryOptions = (signerOrOptions: any) => {
if (!signerOrOptions || signerOrOptions === undefined || signerOrOptions instanceof ethers.Signer) return false

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.42",
"version": "0.5.45",
"description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": {
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
@ -25,8 +25,8 @@
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-astwalker": "^0.0.63",
"@remix-project/remix-lib": "^0.5.40",
"@remix-project/remix-astwalker": "^0.0.66",
"@remix-project/remix-lib": "^0.5.43",
"async": "^2.6.2",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220",
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1",
"main": "./src/index.js"
}
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
"version": "0.0.63",
"version": "0.0.66",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.40",
"@remix-project/remix-lib": "^0.5.43",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethers": "^5.4.2",
@ -53,6 +53,6 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220",
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1",
"types": "./src/index.d.ts"
}
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
"version": "0.5.33",
"version": "0.5.36",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@ -26,10 +26,10 @@
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-astwalker": "^0.0.63",
"@remix-project/remix-lib": "^0.5.40",
"@remix-project/remix-simulator": "^0.2.33",
"@remix-project/remix-solidity": "^0.5.19",
"@remix-project/remix-astwalker": "^0.0.66",
"@remix-project/remix-lib": "^0.5.43",
"@remix-project/remix-simulator": "^0.2.36",
"@remix-project/remix-solidity": "^0.5.22",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -69,6 +69,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220",
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1",
"types": "./src/index.d.ts"
}
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
"version": "0.5.40",
"version": "0.5.43",
"description": "Library to various Remix tools",
"contributors": [
{
@ -19,10 +19,12 @@
"dependencies": {
"@ethereumjs/util": "^8.0.5",
"async": "^2.1.2",
"create-hash": "^1.2.0",
"ethers": "^5.7.2",
"ethjs-util": "^0.1.6",
"events": "^3.0.0",
"from-exponential": "1.1.1",
"rlp": "^3.0.0",
"solc": "^0.7.4",
"string-similarity": "^4.0.4",
"web3": "^4.1.1",
@ -53,6 +55,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220",
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1",
"types": "./src/index.d.ts"
}
}

@ -14,10 +14,10 @@ export function encodeParams (funABI, args) {
if (funABI.inputs && funABI.inputs.length) {
for (let i = 0; i < funABI.inputs.length; i++) {
const type = funABI.inputs[i].type
// "false" will be converting to `false` and "true" will be working
// fine as abiCoder assume anything in quotes as `true`
if (type === 'bool' && args[i] === 'false') {
args[i] = false
if (type === 'bool') {
if (args[i] === false || args[i] === 'false' || args[i] === '0' || args[i] === 0) args[i] = false
else if (args[i] === true || args[i] === 'true' || args[i] === '1' || args[i] === 1) args[i] = true
else throw new Error(`provided value for boolean is invalid: ${args[i]}`)
}
types.push(type.indexOf('tuple') === 0 ? makeFullTypeDefinition(funABI.inputs[i]) : type)
if (args.length < types.length) {

@ -2,7 +2,7 @@
import { EventManager } from '../eventManager'
import type { Transaction as InternalTransaction } from './txRunner'
import Web3 from 'web3'
import {toBigInt} from 'web3-utils'
import {toBigInt, toHex} from 'web3-utils'
export class TxRunnerWeb3 {
event
@ -23,15 +23,15 @@ export class TxRunnerWeb3 {
// this is to avoid the following issue: https://github.com/MetaMask/metamask-extension/issues/11824
tx.type = '0x2'
} else {
tx.type = '0x1'
// tx.type = '0x1'
}
if (txFee) {
if (txFee.baseFeePerGas) {
tx.maxPriorityFeePerGas = this.getWeb3().utils.toHex(this.getWeb3().utils.toWei(txFee.maxPriorityFee, 'gwei'))
tx.maxFeePerGas = this.getWeb3().utils.toHex(this.getWeb3().utils.toWei(txFee.maxFee, 'gwei'))
tx.maxPriorityFeePerGas = toHex(BigInt(this.getWeb3().utils.toWei(txFee.maxPriorityFee, 'gwei')))
tx.maxFeePerGas = toHex(BigInt(this.getWeb3().utils.toWei(txFee.maxFee, 'gwei')))
tx.type = '0x2'
} else {
tx.gasPrice = this.getWeb3().utils.toHex(this.getWeb3().utils.toWei(txFee.gasPrice, 'gwei'))
tx.gasPrice = toHex(BigInt(this.getWeb3().utils.toWei(txFee.gasPrice, 'gwei')))
tx.type = '0x1'
}
}
@ -81,7 +81,7 @@ export class TxRunnerWeb3 {
)
} else {
try {
const res = await this.getWeb3().eth.sendTransaction(tx)
const res = await this.getWeb3().eth.sendTransaction(tx, null, { checkRevertBeforeSending: false })
cb(null, res.transactionHash)
} catch (e) {
console.log(`Send transaction failed: ${e.message} . if you use an injected provider, please check it is properly unlocked. `)
@ -175,16 +175,22 @@ export class TxRunnerWeb3 {
}
}
async function tryTillReceiptAvailable (txhash, web3) {
async function tryTillReceiptAvailable (txhash: string, web3: Web3) {
try {
const receipt = await web3.eth.getTransactionReceipt(txhash)
if (receipt) return receipt
if (receipt) {
if (!receipt.to && !receipt.contractAddress) {
// this is a contract creation and the receipt doesn't contain a contract address. we have to keep polling...
console.log('this is a contract creation and the receipt does nott contain a contract address. we have to keep polling...')
} else
return receipt
}
} catch (e) {}
await pause()
return await tryTillReceiptAvailable(txhash, web3)
}
async function tryTillTxAvailable (txhash, web3) {
async function tryTillTxAvailable (txhash: string, web3: Web3) {
try {
const tx = await web3.eth.getTransaction(txhash)
if (tx && tx.blockHash) return tx

@ -158,7 +158,7 @@ export const ripemd160FromArray = function(a: number[], padded: boolean): Buffer
* @param a The input data
*/
export const rlphash = function(a: Input): Buffer {
return keccak(encode(a))
return keccak(Buffer.from(encode(a)))
}
/**

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
"version": "0.2.33",
"version": "0.2.36",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@ -22,7 +22,7 @@
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.40",
"@remix-project/remix-lib": "^0.5.43",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@ -34,6 +34,7 @@
"express": "^4.16.3",
"express-ws": "^4.0.0",
"merge": "^1.2.0",
"rlp": "^3.0.0",
"string-similarity": "^4.0.4",
"time-stamp": "^2.0.0",
"web3": "^4.1.1",
@ -68,6 +69,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220",
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1",
"types": "./src/index.d.ts"
}
}

@ -158,7 +158,10 @@ export class Transactions {
this.vmContext.web3().flagNextAsDoNotRecordEvmSteps()
processTx(this.txRunnerInstance, payload, true, (error, value: VMexecutionResult) => {
if (error) return cb(error)
const result: RunTxResult = value.result
const result: any = value.result
if (result.execResult && result.execResult.exceptionError && result.execResult.exceptionError.errorType === 'EvmError') {
return cb(result.execResult.exceptionError.error)
}
if ((result as any).receipt?.status === '0x0' || (result as any).receipt?.status === 0) {
try {
const msg = `0x${result.execResult.returnValue.toString('hex') || '0'}`
@ -265,7 +268,7 @@ export class Transactions {
blockHash: '0x' + txBlock.hash().toString('hex'),
blockNumber: bigIntToHex(txBlock.header.number),
from: receipt.from,
gas: toHex(receipt.gas),
gas: toHex(BigInt(receipt.gas)),
chainId: '0xd05',
// 'gasPrice': '2000000000000', // 0x123
gasPrice: '0x4a817c800', // 20000000000
@ -314,7 +317,7 @@ export class Transactions {
blockHash: '0x' + txBlock.hash().toString('hex'),
blockNumber: bigIntToHex(txBlock.header.number),
from: receipt.from,
gas: toHex(receipt.gas),
gas: toHex(BigInt(receipt.gas)),
chainId: '0xd05',
// 'gasPrice': '2000000000000', // 0x123
gasPrice: '0x4a817c800', // 20000000000
@ -359,7 +362,7 @@ export class Transactions {
blockHash: '0x' + txBlock.hash().toString('hex'),
blockNumber: bigIntToHex(txBlock.header.number),
from: receipt.from,
gas: toHex(receipt.gas),
gas: toHex(BigInt(receipt.gas)),
// 'gasPrice': '2000000000000', // 0x123
chainId: '0xd05',
gasPrice: '0x4a817c800', // 20000000000

@ -71,7 +71,7 @@ class StateManagerCommonStorageDump extends DefaultStateManager {
const stream = trie.createReadStream()
stream.on('data', (val) => {
const value = decode(val.value)
const value: any = decode(val.value)
storage['0x' + val.key.toString('hex')] = {
key: this.keyHashes[val.key.toString('hex')],
value: '0x' + value.toString('hex')

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
"version": "0.5.19",
"version": "0.5.22",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -19,7 +19,7 @@
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.40",
"@remix-project/remix-lib": "^0.5.43",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethers": "^5.4.2",
@ -57,5 +57,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220"
}
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
"version": "0.2.33",
"version": "0.2.36",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@ -41,9 +41,9 @@
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-lib": "^0.5.40",
"@remix-project/remix-simulator": "^0.2.33",
"@remix-project/remix-solidity": "^0.5.19",
"@remix-project/remix-lib": "^0.5.43",
"@remix-project/remix-simulator": "^0.2.36",
"@remix-project/remix-solidity": "^0.5.22",
"@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
@ -78,5 +78,5 @@
"typescript": "^3.3.1"
},
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220"
}
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1"
}

@ -26,14 +26,14 @@ export function LanguageOptions({ plugin }: { plugin: any }) {
return (
<>
<div className={langOptions !== 'fr' ? `d-flex align-items-center justify-content-end mr-2` : `d-flex align-items-center justify-content-end mr-3`}>
<div style={{position: 'absolute', right: "1rem", paddingTop: "0.4rem"}}>
<Dropdown>
<Dropdown.Toggle title={langOptions} id="languagedropdown" size="sm">
<Dropdown.Toggle title={langOptions} id="languagedropdown" size="sm" style={{backgroundColor: 'var(--secondary)'}}>
{langOptions}
</Dropdown.Toggle>
<Dropdown.Menu className="dropdown-menu langSelector" style={{ minWidth: '2rem', backgroundColor: 'var(--body-bg)'}}>
<Dropdown.Menu className="dropdown-menu langSelector" style={{ paddingTop: "0px", paddingBottom: "0px", minWidth: 'fit-content', backgroundColor: 'var(--body-bg)'}}>
{['EN', 'ES', 'FR', 'IT', 'ZH'].map((lang, index) => (
<DropdownItem as={'span'} className="p-2" onClick={() =>
<DropdownItem as={'span'} className={langOptions === lang ? "border border-primary px-2" : "px-2"} onClick={() =>
{
changeLanguage(lang.toLowerCase())
setLangOptions(lang)

@ -26,9 +26,8 @@ export function MainnetPrompt(props: MainnetProps) {
const onMaxFeeChange = (value: string) => {
const maxFee = value
// @ts-ignore
if (toBN(props.network.lastBlock.baseFeePerGas).gt(toBN(toWei(maxFee, 'Gwei')))) {
setTransactionFee(intl.formatMessage({id: 'udapp.transactionFeeText'}))
if (toBigInt(props.network.lastBlock.baseFeePerGas) > toBigInt(toWei(maxFee, 'Gwei'))) {
setTransactionFee(intl.formatMessage({id: 'udapp.transactionFee'}))
props.updateGasPriceStatus(false)
props.updateConfirmSettings(true)
return

@ -345,6 +345,8 @@ export const CompilerApiMixin = (Base) => class extends Base {
if(await this.getAppParameter('hardhat-compilation')) this.compileTabLogic.runCompiler('hardhat')
else if(await this.getAppParameter('truffle-compilation')) this.compileTabLogic.runCompiler('truffle')
else this.compileTabLogic.runCompiler(undefined)
} else if (this.currentFile && this.currentFile.endsWith('.circom')) {
await this.call('circuit-compiler', 'compile', this.currentFile)
}
}
}

@ -47,7 +47,7 @@ const Context = ({opts, provider}: {opts; provider: string}) => {
<div>
<span>
<span className="remix_ui_terminal_tx">
[block:{block} txIndex:{i}]
[block:{block.toString()} txIndex:{i ? i.toString() : '-'}]
</span>
<div className="remix_ui_terminal_txItem">
<span className="remix_ui_terminal_txItemTitle">from:</span> {from}
@ -76,7 +76,7 @@ const Context = ({opts, provider}: {opts; provider: string}) => {
<div>
<span>
<span className="remix_ui_terminal_tx">
[block:{block} txIndex:{i}]
[block:{block.toString()} txIndex:{i ? i.toString() : '-'}]
</span>
<div className="remix_ui_terminal_txItem">
<span className="remix_ui_terminal_txItemTitle">from:</span> {from}

@ -75,8 +75,8 @@ const showTable = (opts, showTableHash) => {
<FormattedMessage id="terminal.blockNumber" />
</td>
<td className="remix_ui_terminal_td" data-id={`txLoggerTableContractAddress${opts.hash}`} data-shared={`pair_${opts.hash}`}>
{opts.blockNumber}
<CopyToClipboard content={opts.blockNumber} />
{opts.blockNumber.toString()}
<CopyToClipboard content={opts.blockNumber.toString()} />
</td>
</tr>
) : null}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-url-resolver",
"version": "0.0.62",
"version": "0.0.65",
"description": "Solidity import url resolver engine",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -40,5 +40,5 @@
"typescript": "^3.1.6"
},
"typings": "src/index.d.ts",
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220"
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-ws-templates",
"version": "1.0.27",
"version": "1.0.30",
"description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -24,5 +24,5 @@
"ethers": "^5.4.2",
"web3": "^4.1.1"
},
"gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220"
}
"gitHead": "b8606fe2db170b6ef7cdd19b498db74cf2fb14b1"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remixd",
"version": "0.6.18",
"version": "0.6.19",
"description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)",
"main": "index.js",
"types": "./index.d.ts",

@ -1,6 +1,6 @@
{
"name": "remix-project",
"version": "0.37.0-dev",
"version": "0.38.0-dev",
"license": "MIT",
"description": "Ethereum Remix Monorepo",
"main": "index.js",
@ -159,6 +159,7 @@
"commander": "^9.4.1",
"core-js": "^3.6.5",
"cors": "^2.8.5",
"create-hash": "^1.2.0",
"deep-equal": "^1.0.1",
"document-register-element": "1.13.1",
"electron-squirrel-startup": "^1.0.0",
@ -206,6 +207,7 @@
"react-tabs": "^3.2.2",
"react-zoom-pan-pinch": "^3.0.2",
"regenerator-runtime": "0.13.7",
"rlp": "^3.0.0",
"remark-gfm": "^3.0.1",
"rss-parser": "^3.12.0",
"signale": "^1.4.0",

Loading…
Cancel
Save