diff --git a/apps/contract-verification/src/profile.json b/apps/contract-verification/src/profile.json index f56f684c71..1cc07d5b72 100644 --- a/apps/contract-verification/src/profile.json +++ b/apps/contract-verification/src/profile.json @@ -6,7 +6,7 @@ "events": [], "methods": [], "kind": "none", - "icon": "data:image/png;base64,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", + "icon": "data:image/png;base64,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", "location": "sidePanel", "url": "", "repo": "https://github.com/ethereum/remix-project/tree/master/apps/contract-verification", diff --git a/apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts b/apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts index 48270c6b9b..2ea64cd43b 100644 --- a/apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts +++ b/apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts @@ -19,11 +19,11 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat .waitForElementVisible('.ataddressinput') .click('.ataddressinput') .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) { browser .click({ - selector: '//*[@id="runAndDeployAtAdressButtonContainer"]', + selector: '//*[@id="runAndDeployAtAddressButtonContainer"]', locateStrategy: 'xpath' }) .waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]', 5000) @@ -34,7 +34,7 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat }) } else { browser.click({ - selector: '//*[@id="runAndDeployAtAdressButtonContainer"]', + selector: '//*[@id="runAndDeployAtAddressButtonContainer"]', locateStrategy: 'xpath' }) } diff --git a/apps/remix-ide/src/app/tabs/locales/en/home.json b/apps/remix-ide/src/app/tabs/locales/en/home.json index a638fd2b02..e4e5554eb4 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/home.json +++ b/apps/remix-ide/src/app/tabs/locales/en/home.json @@ -26,6 +26,7 @@ "home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.", "home.sourcifyPluginDesc": "Solidity contract and metadata verification service.", "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.oneClickDappDesc": "Quickly generate smart contract interfaces", "home.getStarted": "Get Started", diff --git a/apps/remix-ide/src/assets/img/contractVerification.webp b/apps/remix-ide/src/assets/img/contractVerification.webp new file mode 100644 index 0000000000..6d7dd5ae6d Binary files /dev/null and b/apps/remix-ide/src/assets/img/contractVerification.webp differ diff --git a/apps/remix-ide/team-best-practices.md b/apps/remix-ide/team-best-practices.md index 2088cd5bf9..477f1304a0 100644 --- a/apps/remix-ide/team-best-practices.md +++ b/apps/remix-ide/team-best-practices.md @@ -158,7 +158,7 @@ Before starting to coding, we should ensure all devs / contributors are aware of ### 1) Bugs: - 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: - - 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. ### 2) Support: diff --git a/libs/remix-lib/src/execution/txRunnerVM.ts b/libs/remix-lib/src/execution/txRunnerVM.ts index 6c4c40b27b..12bfd3636e 100644 --- a/libs/remix-lib/src/execution/txRunnerVM.ts +++ b/libs/remix-lib/src/execution/txRunnerVM.ts @@ -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) { const { to, data, value, gasLimit, useCall, signed } = tx let { from } = tx @@ -183,7 +210,7 @@ export class TxRunnerVM { const result: RunTxResult = results.results[0] callback(null, { result, - transactionHash: bytesToHex(Buffer.from(tx.hash())), + transactionHash: tx ? bytesToHex(Buffer.from(tx.hash())) : null, block, tx }) diff --git a/libs/remix-simulator/README.md b/libs/remix-simulator/README.md index a7921c7c9e..4c3717fefc 100644 --- a/libs/remix-simulator/README.md +++ b/libs/remix-simulator/README.md @@ -39,7 +39,7 @@ * [X] eth_getCode * [~] eth_sign * [X] eth_sendTransaction -* [_] eth_sendRawTransaction +* [x] eth_sendRawTransaction * [X] eth_call * [~] eth_estimateGas * [X] eth_getBlockByHash diff --git a/libs/remix-simulator/src/methods/accounts.ts b/libs/remix-simulator/src/methods/accounts.ts index c28818c8e6..c35e7f46a6 100644 --- a/libs/remix-simulator/src/methods/accounts.ts +++ b/libs/remix-simulator/src/methods/accounts.ts @@ -1,7 +1,7 @@ import { signTypedData, SignTypedDataVersion, TypedMessage, MessageTypes } from '@metamask/eth-sig-util' import { privateToAddress, toChecksumAddress, isValidPrivate, Address, toBytes, bytesToHex, Account } from '@ethereumjs/util' import { privateKeyToAccount } from 'web3-eth-accounts' -import { toBigInt } from 'web3-utils' +import { toBigInt, toHex } from 'web3-utils' import * as crypto from 'crypto' type AccountType = { @@ -13,9 +13,11 @@ export class Web3Accounts { accounts: Record accountsKeys: Record vmContext + options - constructor (vmContext) { + constructor (vmContext, options) { this.vmContext = vmContext + this.options = options // TODO: make it random and/or use remix-libs this.accounts = {} @@ -97,6 +99,8 @@ export class Web3Accounts { eth_getBalance (payload, cb) { const address = payload.params[0] 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)) }).catch((error) => { cb(error) @@ -119,7 +123,9 @@ export class Web3Accounts { } 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) { diff --git a/libs/remix-simulator/src/methods/evm.ts b/libs/remix-simulator/src/methods/evm.ts new file mode 100644 index 0000000000..16fde3c180 --- /dev/null +++ b/libs/remix-simulator/src/methods/evm.ts @@ -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() + } +} diff --git a/libs/remix-simulator/src/methods/miner.ts b/libs/remix-simulator/src/methods/miner.ts new file mode 100644 index 0000000000..b44058f5a7 --- /dev/null +++ b/libs/remix-simulator/src/methods/miner.ts @@ -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() } +} diff --git a/libs/remix-simulator/src/methods/net.ts b/libs/remix-simulator/src/methods/net.ts index 1a064719f4..3c9c7a612c 100644 --- a/libs/remix-simulator/src/methods/net.ts +++ b/libs/remix-simulator/src/methods/net.ts @@ -1,20 +1,24 @@ -export function methods (): Record { - return { - net_version: net_version, - net_listening: net_listening, - net_peerCount: net_peerCount +export class Net { + vmContext + options + + constructor (vmContext, options) { + this.vmContext = vmContext + this.options = options } -} -export function net_version (payload, cb): void { - // should be configured networkId - cb(null, 1337) -} + methods () { + return { + net_version: this.net_version.bind(this), + net_listening: this.net_listening.bind(this), + net_peerCount: this.net_peerCount.bind(this) + } + } -export function net_listening (payload, cb): void { - cb(null, true) -} + net_version (payload, cb) { cb(null, 1337) } + + net_listening (payload, cb) { cb(null, true)} -export function net_peerCount (payload, cb): void { - cb(null, 0) + net_peerCount (payload, cb) { cb(null, 0)} } + diff --git a/libs/remix-simulator/src/provider.ts b/libs/remix-simulator/src/provider.ts index b6c52345fe..8fae322c6b 100644 --- a/libs/remix-simulator/src/provider.ts +++ b/libs/remix-simulator/src/provider.ts @@ -6,9 +6,11 @@ import merge from 'merge' import { Web3Accounts } from './methods/accounts' import { Filters } from './methods/filters' 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 { Miner } from './methods/miner' import { Debug } from './methods/debug' +import { EVM } from './methods/evm' import { VMContext } from './vm-context' import { Web3PluginBase } from 'web3' @@ -30,6 +32,7 @@ export type JSONRPCResponseCallback = (err: Error, result?: JSONRPCResponsePaylo export type State = Record export type ProviderOptions = { + chainId?: number fork?: string, nodeUrl?: string, blockNumber?: number | 'latest', @@ -47,14 +50,16 @@ export class Provider { methods connected: boolean initialized: boolean + initializing: boolean pendingRequests: Array constructor (options: ProviderOptions = {} as ProviderOptions) { + console.log(options) this.options = options this.connected = true 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.methods = {} @@ -62,12 +67,15 @@ export class Provider { this.methods = merge(this.methods, (new Blocks(this.vmContext, options)).methods()) this.methods = merge(this.methods, miscMethods()) 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, (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 () { + this.initializing = true this.initialized = false this.pendingRequests = [] await this.vmContext.init() @@ -80,6 +88,7 @@ export class Provider { }) this.pendingRequests = [] } + this.initializing = false } _send(payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) { diff --git a/libs/remix-simulator/test/blocks.ts b/libs/remix-simulator/test/blocks.ts index e0eb39d6c9..0b4b2ad52c 100644 --- a/libs/remix-simulator/test/blocks.ts +++ b/libs/remix-simulator/test/blocks.ts @@ -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', () => { it('should get block given its hash', async () => { const correctBlock = await web3.eth.getBlock(0) diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx index 199a141ee7..eb01655998 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx @@ -82,6 +82,11 @@ function HomeTabFeaturedPlugins({ plugin }: HomeTabFeaturedPluginsProps) { plugin.verticalIcons.select('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 (
@@ -116,14 +121,14 @@ function HomeTabFeaturedPlugins({ plugin }: HomeTabFeaturedPluginsProps) { itemClass="w-100" > startCodeAnalyzer()} + maintainedBy="Remix" + callback={() => startContractVerification()} /> startLearnEth()} /> + startCodeAnalyzer()} + /> { + const [is_streaming, setIS_streaming] = useState(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 ( prompt: string, observer: StreamingAdapterObserver, ) => { GenerationParams.stream_result = true + setIS_streaming(true) GenerationParams.return_stream_response = GenerationParams.stream_result let response = null @@ -32,13 +56,15 @@ export const Default = (props) => { observer.next(' ') // Add a space to flush the last message ChatHistory.pushHistory(prompt, result) observer.complete() + setTimeout(() => { setIS_streaming(false) }, 1000) } ) else { observer.next(response) observer.complete() - } + setTimeout(() => { setIS_streaming(false) }, 1000) + } }; ChatApi = useAiChatApi(); const conversationStarters: ConversationStarter[] = [ @@ -73,9 +99,9 @@ export const Default = (props) => { submitShortcut: 'Enter', hideStopButton: false, }} - messageOptions={{ showCodeBlockCopyButton: false, + messageOptions={{ showCodeBlockCopyButton: true, editableUserMessages: true, - streamingAnimationSpeed: 2, + streamingAnimationSpeed: 1, waitTimeBeforeStreamCompletion: 1000, syntaxHighlighter: highlighter }} diff --git a/libs/remix-ui/run-tab/src/lib/actions/index.ts b/libs/remix-ui/run-tab/src/lib/actions/index.ts index a8c914b9c7..134b88c007 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/index.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/index.ts @@ -66,4 +66,4 @@ export const setNetworkName = (networkName: string) => setNetworkNameFromProvide export const updateSelectedContract = (contractName) => setSelectedContract(dispatch, contractName) export const syncContracts = () => syncContractsInternal(plugin) export const isValidProxyAddress = (address: string) => isValidContractAddress(plugin, address) -export const isValidProxyUpgrade = (proxyAddress: string, contractName: string, solcInput: SolcInput, solcOutput: SolcOutput, solcVersion: string) => isValidContractUpgrade(plugin, proxyAddress, contractName, solcInput, solcOutput, solcVersion) +export const isValidProxyUpgrade = (proxyAddress: string, contractName: string, solcInput: SolcInput, solcOutput: SolcOutput, solcVersion: string) => isValidContractUpgrade(plugin, proxyAddress, contractName, solcInput, solcOutput, solcVersion) \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx b/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx index b2a6573874..14ecd27699 100644 --- a/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx @@ -517,10 +517,10 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
-
+