Merge branch 'master' into pastedCodeSafety

pull/5344/head
STetsing 3 weeks ago committed by GitHub
commit 135e11af82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      apps/contract-verification/src/profile.json
  2. 6
      apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts
  3. 1
      apps/remix-ide/src/app/tabs/locales/en/home.json
  4. BIN
      apps/remix-ide/src/assets/img/contractVerification.webp
  5. 2
      apps/remix-ide/team-best-practices.md
  6. 29
      libs/remix-lib/src/execution/txRunnerVM.ts
  7. 2
      libs/remix-simulator/README.md
  8. 12
      libs/remix-simulator/src/methods/accounts.ts
  9. 79
      libs/remix-simulator/src/methods/evm.ts
  10. 18
      libs/remix-simulator/src/methods/miner.ts
  11. 30
      libs/remix-simulator/src/methods/net.ts
  12. 15
      libs/remix-simulator/src/provider.ts
  13. 11
      libs/remix-simulator/test/blocks.ts
  14. 27
      libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx
  15. 38
      libs/remix-ui/remix-ai/src/lib/components/Default.tsx
  16. 4
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  17. 2
      libs/remix-ui/run-tab/src/lib/types/index.ts
  18. 4
      libs/remix-url-resolver/src/resolve.ts

File diff suppressed because one or more lines are too long

@ -19,11 +19,11 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat
.waitForElementVisible('.ataddressinput') .waitForElementVisible('.ataddressinput')
.click('.ataddressinput') .click('.ataddressinput')
.setValue('.ataddressinput', address, function () { .setValue('.ataddressinput', address, function () {
if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAdressButton"]:disabled') if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAddressButton"]:disabled')
else if (isAbi) { else if (isAbi) {
browser browser
.click({ .click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]', selector: '//*[@id="runAndDeployAtAddressButtonContainer"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}) })
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]', 5000) .waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]', 5000)
@ -34,7 +34,7 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat
}) })
} else { } else {
browser.click({ browser.click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]', selector: '//*[@id="runAndDeployAtAddressButtonContainer"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}) })
} }

@ -26,6 +26,7 @@
"home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.", "home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.",
"home.sourcifyPluginDesc": "Solidity contract and metadata verification service.", "home.sourcifyPluginDesc": "Solidity contract and metadata verification service.",
"home.unitTestPluginDesc": "Write and run unit tests for your contracts in Solidity.", "home.unitTestPluginDesc": "Write and run unit tests for your contracts in Solidity.",
"home.contractVerificationDesc": "Verify contracts on multiple services at the same time.",
"home.dgitPluginDesc": "Add source control to your projects.", "home.dgitPluginDesc": "Add source control to your projects.",
"home.oneClickDappDesc": "Quickly generate smart contract interfaces", "home.oneClickDappDesc": "Quickly generate smart contract interfaces",
"home.getStarted": "Get Started", "home.getStarted": "Get Started",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -158,7 +158,7 @@ Before starting to coding, we should ensure all devs / contributors are aware of
### 1) Bugs: ### 1) Bugs:
- A critical bug should get the label `Blocker`, and every effort should be put to fix it. - A critical bug should get the label `Blocker`, and every effort should be put to fix it.
- Addressing a non critical and non planned bug can be done: - Addressing a non critical and non planned bug can be done:
- After having notified in the `remix-dev` channel if the bug does not involves UX or public API changes. - After having notified in the `remix-dev` channel if the bug does not involve UX or public API changes.
- After a dev meeting (e.g the regular standup) if the bug involves any UX or public API changes. - After a dev meeting (e.g the regular standup) if the bug involves any UX or public API changes.
### 2) Support: ### 2) Support:

@ -75,6 +75,33 @@ export class TxRunnerVM {
} }
} }
runEmptyBlock (callback: VMExecutionCallBack) {
const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle.
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [69762765929000, 70762765929000, 71762765929000]
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blocks.length % difficulties.length]
const block = Block.fromBlockData({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: this.blocks.length,
coinbase: coinbases[this.blocks.length % coinbases.length],
difficulty,
gasLimit: 0,
baseFeePerGas: EIP1559 ? '0x1' : undefined,
parentHash: this.blockParentHash
}
}, { common: this.commonContext })
this.blockParentHash = block.hash()
this.runBlockInVm(null, block, async (err, result) => {
if (!err) {
this.getVMObject().vm.blockchain.putBlock(block)
this.blocks.push(block.serialize())
}
callback(err, result)
})
}
async runInVm (tx: InternalTransaction, callback: VMExecutionCallBack) { async runInVm (tx: InternalTransaction, callback: VMExecutionCallBack) {
const { to, data, value, gasLimit, useCall, signed } = tx const { to, data, value, gasLimit, useCall, signed } = tx
let { from } = tx let { from } = tx
@ -183,7 +210,7 @@ export class TxRunnerVM {
const result: RunTxResult = results.results[0] const result: RunTxResult = results.results[0]
callback(null, { callback(null, {
result, result,
transactionHash: bytesToHex(Buffer.from(tx.hash())), transactionHash: tx ? bytesToHex(Buffer.from(tx.hash())) : null,
block, block,
tx tx
}) })

@ -39,7 +39,7 @@
* [X] eth_getCode * [X] eth_getCode
* [~] eth_sign * [~] eth_sign
* [X] eth_sendTransaction * [X] eth_sendTransaction
* [_] eth_sendRawTransaction * [x] eth_sendRawTransaction
* [X] eth_call * [X] eth_call
* [~] eth_estimateGas * [~] eth_estimateGas
* [X] eth_getBlockByHash * [X] eth_getBlockByHash

@ -1,7 +1,7 @@
import { signTypedData, SignTypedDataVersion, TypedMessage, MessageTypes } from '@metamask/eth-sig-util' import { signTypedData, SignTypedDataVersion, TypedMessage, MessageTypes } from '@metamask/eth-sig-util'
import { privateToAddress, toChecksumAddress, isValidPrivate, Address, toBytes, bytesToHex, Account } from '@ethereumjs/util' import { privateToAddress, toChecksumAddress, isValidPrivate, Address, toBytes, bytesToHex, Account } from '@ethereumjs/util'
import { privateKeyToAccount } from 'web3-eth-accounts' import { privateKeyToAccount } from 'web3-eth-accounts'
import { toBigInt } from 'web3-utils' import { toBigInt, toHex } from 'web3-utils'
import * as crypto from 'crypto' import * as crypto from 'crypto'
type AccountType = { type AccountType = {
@ -13,9 +13,11 @@ export class Web3Accounts {
accounts: Record<string, AccountType> accounts: Record<string, AccountType>
accountsKeys: Record<string, string> accountsKeys: Record<string, string>
vmContext vmContext
options
constructor (vmContext) { constructor (vmContext, options) {
this.vmContext = vmContext this.vmContext = vmContext
this.options = options
// TODO: make it random and/or use remix-libs // TODO: make it random and/or use remix-libs
this.accounts = {} this.accounts = {}
@ -97,6 +99,8 @@ export class Web3Accounts {
eth_getBalance (payload, cb) { eth_getBalance (payload, cb) {
const address = payload.params[0] const address = payload.params[0]
this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => { this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => {
if (!account) return cb(null, toBigInt(0).toString(10))
if (!account.balance) return cb(null, toBigInt(0).toString(10))
cb(null, toBigInt(account.balance).toString(10)) cb(null, toBigInt(account.balance).toString(10))
}).catch((error) => { }).catch((error) => {
cb(error) cb(error)
@ -119,7 +123,9 @@ export class Web3Accounts {
} }
eth_chainId (_payload, cb) { eth_chainId (_payload, cb) {
return cb(null, '0x539') // 0x539 is hex of 1337 if (!this.options.chainId) return cb(null, '0x539') // 0x539 is hex of 1337
const id = (typeof this.options.chainId === 'number') ? toHex(this.options.chainId) : this.options.chainId
return cb(null, id)
} }
eth_signTypedData_v4 (payload, cb) { eth_signTypedData_v4 (payload, cb) {

@ -0,0 +1,79 @@
import { Block } from '@ethereumjs/block'
import { ConsensusType } from '@ethereumjs/common'
import type { VMContext } from '../vm-context'
import type { Transactions } from '../methods/transactions'
export class EVM {
vmContext: VMContext
transactions: Transactions
constructor (vmContext: VMContext, transactions: Transactions) {
this.vmContext = vmContext
this.transactions = transactions
}
methods () {
return {
evm_setAutomine: this.evm_setAutomine.bind(this),
evm_setIntervalMining: this.evm_setIntervalMining.bind(this),
evm_snapshot: this.evm_snapshot.bind(this),
evm_revert: this.evm_revert.bind(this),
evm_increaseTime: this.evm_increaseTime.bind(this),
evm_setNextBlockTimestamp: this.evm_setNextBlockTimestamp.bind(this),
evm_setBlockGasLimit: this.evm_setBlockGasLimit.bind(this),
evm_mine: this.evm_mine.bind(this)
}
}
evm_setAutomine (payload, cb) {
// always on
cb()
}
evm_setIntervalMining (payload, cb) {
cb()
}
evm_snapshot (payload, cb) {
cb()
}
evm_revert (payload, cb) {
cb()
}
evm_increaseTime (payload, cb) {
cb()
}
evm_setNextBlockTimestamp (payload, cb) {
cb()
}
evm_setBlockGasLimit (payload, cb) {
cb()
}
async evm_mine (payload, cb) {
const runEmptyBlock = () => {
return new Promise((resolve, reject) => {
this.transactions.txRunnerVMInstance.runEmptyBlock((error, result) => {
if (error) {
reject(error)
return
}
this.vmContext.addBlock(result.block, false, true)
resolve(result)
})
})
}
const blocks = payload.params[0].blocks
for (let b = 0; b < Number(blocks); b++) {
await runEmptyBlock()
console.log('mining...', b, this.vmContext.latestBlockNumber)
}
cb()
}
}

@ -0,0 +1,18 @@
export class Miner {
vmContext
constructor (vmContext) {
this.vmContext = vmContext
}
methods () {
return {
miner_start: this.miner_start.bind(this),
miner_stop: this.miner_stop.bind(this)
}
}
miner_start (payload, cb) { cb() }
miner_stop (payload, cb) { cb() }
}

@ -1,20 +1,24 @@
export function methods (): Record<string, unknown> { export class Net {
vmContext
options
constructor (vmContext, options) {
this.vmContext = vmContext
this.options = options
}
methods () {
return { return {
net_version: net_version, net_version: this.net_version.bind(this),
net_listening: net_listening, net_listening: this.net_listening.bind(this),
net_peerCount: net_peerCount net_peerCount: this.net_peerCount.bind(this)
} }
} }
export function net_version (payload, cb): void { net_version (payload, cb) { cb(null, 1337) }
// should be configured networkId
cb(null, 1337)
}
export function net_listening (payload, cb): void { net_listening (payload, cb) { cb(null, true)}
cb(null, true)
}
export function net_peerCount (payload, cb): void { net_peerCount (payload, cb) { cb(null, 0)}
cb(null, 0)
} }

@ -6,9 +6,11 @@ import merge from 'merge'
import { Web3Accounts } from './methods/accounts' import { Web3Accounts } from './methods/accounts'
import { Filters } from './methods/filters' import { Filters } from './methods/filters'
import { methods as miscMethods } from './methods/misc' import { methods as miscMethods } from './methods/misc'
import { methods as netMethods } from './methods/net' import { Net } from './methods/net'
import { Transactions } from './methods/transactions' import { Transactions } from './methods/transactions'
import { Miner } from './methods/miner'
import { Debug } from './methods/debug' import { Debug } from './methods/debug'
import { EVM } from './methods/evm'
import { VMContext } from './vm-context' import { VMContext } from './vm-context'
import { Web3PluginBase } from 'web3' import { Web3PluginBase } from 'web3'
@ -30,6 +32,7 @@ export type JSONRPCResponseCallback = (err: Error, result?: JSONRPCResponsePaylo
export type State = Record<string, string> export type State = Record<string, string>
export type ProviderOptions = { export type ProviderOptions = {
chainId?: number
fork?: string, fork?: string,
nodeUrl?: string, nodeUrl?: string,
blockNumber?: number | 'latest', blockNumber?: number | 'latest',
@ -47,14 +50,16 @@ export class Provider {
methods methods
connected: boolean connected: boolean
initialized: boolean initialized: boolean
initializing: boolean
pendingRequests: Array<any> pendingRequests: Array<any>
constructor (options: ProviderOptions = {} as ProviderOptions) { constructor (options: ProviderOptions = {} as ProviderOptions) {
console.log(options)
this.options = options this.options = options
this.connected = true this.connected = true
this.vmContext = new VMContext(options['fork'], options['nodeUrl'], options['blockNumber'], options['stateDb'], options['blocks']) this.vmContext = new VMContext(options['fork'], options['nodeUrl'], options['blockNumber'], options['stateDb'], options['blocks'])
this.Accounts = new Web3Accounts(this.vmContext) this.Accounts = new Web3Accounts(this.vmContext, options)
this.Transactions = new Transactions(this.vmContext) this.Transactions = new Transactions(this.vmContext)
this.methods = {} this.methods = {}
@ -62,12 +67,15 @@ export class Provider {
this.methods = merge(this.methods, (new Blocks(this.vmContext, options)).methods()) this.methods = merge(this.methods, (new Blocks(this.vmContext, options)).methods())
this.methods = merge(this.methods, miscMethods()) this.methods = merge(this.methods, miscMethods())
this.methods = merge(this.methods, (new Filters(this.vmContext)).methods()) this.methods = merge(this.methods, (new Filters(this.vmContext)).methods())
this.methods = merge(this.methods, netMethods()) this.methods = merge(this.methods, (new Net(this.vmContext, options)).methods())
this.methods = merge(this.methods, this.Transactions.methods()) this.methods = merge(this.methods, this.Transactions.methods())
this.methods = merge(this.methods, (new Debug(this.vmContext)).methods()) this.methods = merge(this.methods, (new Debug(this.vmContext)).methods())
this.methods = merge(this.methods, (new EVM(this.vmContext, this.Transactions)).methods())
this.methods = merge(this.methods, (new Miner(this.vmContext)).methods())
} }
async init () { async init () {
this.initializing = true
this.initialized = false this.initialized = false
this.pendingRequests = [] this.pendingRequests = []
await this.vmContext.init() await this.vmContext.init()
@ -80,6 +88,7 @@ export class Provider {
}) })
this.pendingRequests = [] this.pendingRequests = []
} }
this.initializing = false
} }
_send(payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) { _send(payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) {

@ -63,6 +63,17 @@ describe('blocks', () => {
}) })
}) })
describe('evm_mine', () => {
it('should mine empty block using evm_mine', async function () {
await web3.provider.request({
method: 'evm_mine',
params: [{ blocks: 3 }],
})
const number = await web3.eth.getBlockNumber()
assert.equal(number, 3)
})
})
describe('eth_getBlockByHash', () => { describe('eth_getBlockByHash', () => {
it('should get block given its hash', async () => { it('should get block given its hash', async () => {
const correctBlock = await web3.eth.getBlock(0) const correctBlock = await web3.eth.getBlock(0)

@ -82,6 +82,11 @@ function HomeTabFeaturedPlugins({ plugin }: HomeTabFeaturedPluginsProps) {
plugin.verticalIcons.select('solidityUnitTesting') plugin.verticalIcons.select('solidityUnitTesting')
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'solidityUnitTesting']) _paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'solidityUnitTesting'])
} }
const startContractVerification = async () => {
await plugin.appManager.activatePlugin(['contract-verification'])
plugin.verticalIcons.select('contract-verification')
_paq.push(['trackEvent', 'hometabActivate', 'userActivate', 'contract-verification'])
}
return ( return (
<div className="pl-2 w-100 align-items-end remixui_featuredplugins_container" id="hTFeaturedPlugins"> <div className="pl-2 w-100 align-items-end remixui_featuredplugins_container" id="hTFeaturedPlugins">
@ -116,14 +121,14 @@ function HomeTabFeaturedPlugins({ plugin }: HomeTabFeaturedPluginsProps) {
itemClass="w-100" itemClass="w-100"
> >
<PluginButton <PluginButton
imgPath="assets/img/staticAnalysis.webp" imgPath="assets/img/contractVerification.webp"
envID="staticAnalysisLogo" envID="contractVerificationLogo"
envText="Solidity Analyzers" envText="Contract Verification"
description={intl.formatMessage({ description={intl.formatMessage({
id: 'home.codeAnalyizerPluginDesc' id: 'home.contractVerificationDesc',
})} })}
maintainedBy='Remix' maintainedBy="Remix"
callback={() => startCodeAnalyzer()} callback={() => startContractVerification()}
/> />
<PluginButton <PluginButton
imgPath="assets/img/learnEthLogo.webp" imgPath="assets/img/learnEthLogo.webp"
@ -135,6 +140,16 @@ function HomeTabFeaturedPlugins({ plugin }: HomeTabFeaturedPluginsProps) {
maintainedBy='Remix' maintainedBy='Remix'
callback={() => startLearnEth()} callback={() => startLearnEth()}
/> />
<PluginButton
imgPath="assets/img/staticAnalysis.webp"
envID="staticAnalysisLogo"
envText="Solidity Analyzers"
description={intl.formatMessage({
id: 'home.codeAnalyizerPluginDesc'
})}
maintainedBy='Remix'
callback={() => startCodeAnalyzer()}
/>
<PluginButton <PluginButton
imgPath="assets/img/cookbook.webp" imgPath="assets/img/cookbook.webp"
envID="cookbookLogo" envID="cookbookLogo"

@ -1,22 +1,46 @@
import React from 'react' import React, { useState, useEffect } from 'react'
import '../remix-ai.css' import '../remix-ai.css'
import { DefaultModels, GenerationParams, ChatHistory, HandleStreamResponse, HandleSimpleResponse } from '@remix/remix-ai-core'; import { DefaultModels, GenerationParams, ChatHistory, HandleStreamResponse } from '@remix/remix-ai-core';
import { ConversationStarter, StreamSend, StreamingAdapterObserver, useAiChatApi } from '@nlux/react'; import { ConversationStarter, StreamSend, StreamingAdapterObserver, useAiChatApi } from '@nlux/react';
import { AiChat, useAsStreamAdapter, ChatItem } from '@nlux/react'; import { AiChat, useAsStreamAdapter, ChatItem } from '@nlux/react';
import { JsonStreamParser } from '@remix/remix-ai-core';
import { user, assistantAvatar } from './personas'; import { user, assistantAvatar } from './personas';
import { highlighter } from '@nlux/highlighter' import { highlighter } from '@nlux/highlighter'
import './color.css' import './color.css'
import '@nlux/themes/unstyled.css'; import '@nlux/themes/unstyled.css';
import copy from 'copy-to-clipboard'
export let ChatApi = null export let ChatApi = null
export const Default = (props) => { export const Default = (props) => {
const [is_streaming, setIS_streaming] = useState<boolean>(false)
const HandleCopyToClipboard = () => {
const markdown = document.getElementsByClassName('nlux-chatSegments-container')
if (markdown.length < 1) return
const codeBlocks = markdown[0].getElementsByClassName('code-block')
Array.from(codeBlocks).forEach((block) => {
const copyButtons = block.getElementsByClassName('nlux-comp-copyButton')
Array.from(copyButtons).forEach((cp_btn) => {
const hdlr = async () => {
copy(block.textContent)
}
cp_btn.removeEventListener('click', async() => { hdlr() })
cp_btn.addEventListener('click', async () => { hdlr() })
})
})
}
useEffect(() => {
HandleCopyToClipboard();
}, [is_streaming]);
const send: StreamSend = async ( const send: StreamSend = async (
prompt: string, prompt: string,
observer: StreamingAdapterObserver, observer: StreamingAdapterObserver,
) => { ) => {
GenerationParams.stream_result = true GenerationParams.stream_result = true
setIS_streaming(true)
GenerationParams.return_stream_response = GenerationParams.stream_result GenerationParams.return_stream_response = GenerationParams.stream_result
let response = null let response = null
@ -32,13 +56,15 @@ export const Default = (props) => {
observer.next(' ') // Add a space to flush the last message observer.next(' ') // Add a space to flush the last message
ChatHistory.pushHistory(prompt, result) ChatHistory.pushHistory(prompt, result)
observer.complete() observer.complete()
setTimeout(() => { setIS_streaming(false) }, 1000)
} }
) )
else { else {
observer.next(response) observer.next(response)
observer.complete() observer.complete()
}
setTimeout(() => { setIS_streaming(false) }, 1000)
}
}; };
ChatApi = useAiChatApi(); ChatApi = useAiChatApi();
const conversationStarters: ConversationStarter[] = [ const conversationStarters: ConversationStarter[] = [
@ -73,9 +99,9 @@ export const Default = (props) => {
submitShortcut: 'Enter', submitShortcut: 'Enter',
hideStopButton: false, hideStopButton: false,
}} }}
messageOptions={{ showCodeBlockCopyButton: false, messageOptions={{ showCodeBlockCopyButton: true,
editableUserMessages: true, editableUserMessages: true,
streamingAnimationSpeed: 2, streamingAnimationSpeed: 1,
waitTimeBeforeStreamCompletion: 1000, waitTimeBeforeStreamCompletion: 1000,
syntaxHighlighter: highlighter syntaxHighlighter: highlighter
}} }}

@ -517,10 +517,10 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
<div className="pt-2 d-flex flex-column sudapp_button udapp_atAddressSect"> <div className="pt-2 d-flex flex-column sudapp_button udapp_atAddressSect">
<div className="d-flex flex-row"> <div className="d-flex flex-row">
<CustomTooltip placement={'top-end'} tooltipClasses="text-wrap text-left" tooltipId="runAndDeployAddresstooltip" tooltipText={atAddressOptions.title}> <CustomTooltip placement={'top-end'} tooltipClasses="text-wrap text-left" tooltipId="runAndDeployAddresstooltip" tooltipText={atAddressOptions.title}>
<div id="runAndDeployAtAdressButtonContainer" data-title={atAddressOptions.title}> <div id="runAndDeployAtAddressButtonContainer" data-title={atAddressOptions.title}>
<button <button
className={atAddressOptions.disabled ? "disabled udapp_atAddress btn btn-sm py-2 btn-primary" : "udapp_atAddress btn btn-sm py-2 btn-primary"} className={atAddressOptions.disabled ? "disabled udapp_atAddress btn btn-sm py-2 btn-primary" : "udapp_atAddress btn btn-sm py-2 btn-primary"}
id="runAndDeployAtAdressButton" id="runAndDeployAtAddressButton"
disabled={atAddressOptions.disabled} disabled={atAddressOptions.disabled}
style={{ border: 'none' }} style={{ border: 'none' }}
onClick={loadFromAddress} onClick={loadFromAddress}

@ -282,7 +282,7 @@ export interface ContractDropdownProps {
setSelectedContract: (contractName: string) => void setSelectedContract: (contractName: string) => void
remixdActivated: boolean, remixdActivated: boolean,
isValidProxyAddress?: (address: string) => Promise<boolean>, isValidProxyAddress?: (address: string) => Promise<boolean>,
isValidProxyUpgrade?: (proxyAddress: string, contractName: string, solcInput: SolcInput, solcOuput: SolcOutput, solcVersion: string) => Promise<LayoutCompatibilityReport | { ok: boolean, pass: boolean, warning: boolean }>, isValidProxyUpgrade?: (proxyAddress: string, contractName: string, solcInput: SolcInput, solcOutput: SolcOutput, solcVersion: string) => Promise<LayoutCompatibilityReport | { ok: boolean, pass: boolean, warning: boolean }>,
proxy: { deployments: { address: string, date: string, contractName: string }[] } proxy: { deployments: { address: string, date: string, contractName: string }[] }
solCompilerVersion: { version: string, canReceive: boolean } solCompilerVersion: { version: string, canReceive: boolean }
setCompilerVersion: React.Dispatch<React.SetStateAction<{ setCompilerVersion: React.Dispatch<React.SetStateAction<{

@ -140,8 +140,8 @@ export class RemixURLResolver {
async handleNpmImport(url: string): Promise<HandlerResponse> { async handleNpmImport(url: string): Promise<HandlerResponse> {
if (!url) throw new Error('url is empty') if (!url) throw new Error('url is empty')
let fetchUrl = url let fetchUrl = url
const isVersionned = semverRegex().exec(url.replace(/@/g, '@ ').replace(/\//g, ' /')) const isVersioned = semverRegex().exec(url.replace(/@/g, '@ ').replace(/\//g, ' /'))
if (this.getDependencies && !isVersionned) { if (this.getDependencies && !isVersioned) {
try { try {
const { deps, yarnLock, packageLock } = await this.getDependencies() const { deps, yarnLock, packageLock } = await this.getDependencies()
let matchLength = 0 let matchLength = 0

Loading…
Cancel
Save