Merge branch 'master' of https://github.com/ethereum/remix-project into resolve_with_package
commit
b737714a21
File diff suppressed because one or more lines are too long
@ -0,0 +1,136 @@ |
||||
import { Plugin } from '@remixproject/engine' |
||||
import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app' |
||||
import { Blockchain } from '../../blockchain/blockchain' |
||||
import { ethers } from 'ethers' |
||||
|
||||
export type JsonDataRequest = { |
||||
id: number, |
||||
jsonrpc: string // version
|
||||
method: string, |
||||
params: Array<any>, |
||||
} |
||||
|
||||
export type JsonDataResult = { |
||||
id: number, |
||||
jsonrpc: string // version
|
||||
result: any |
||||
} |
||||
|
||||
export type RejectRequest = (error: Error) => void |
||||
export type SuccessRequest = (data: JsonDataResult) => void |
||||
|
||||
export interface IProvider { |
||||
options: { [id: string] : any } |
||||
init(): Promise<{ [id: string] : any }> |
||||
body(): JSX.Element |
||||
sendAsync (data: JsonDataRequest): Promise<JsonDataResult> |
||||
} |
||||
|
||||
export abstract class AbstractProvider extends Plugin implements IProvider { |
||||
provider: ethers.providers.JsonRpcProvider |
||||
blockchain: Blockchain |
||||
defaultUrl: string |
||||
connected: boolean |
||||
nodeUrl: string |
||||
options: { [id: string] : any } = {} |
||||
|
||||
constructor (profile, blockchain, defaultUrl) { |
||||
super(profile) |
||||
this.defaultUrl = defaultUrl |
||||
this.provider = null |
||||
this.connected = false |
||||
this.blockchain = blockchain |
||||
this.nodeUrl = 'http://localhost:8545' |
||||
} |
||||
|
||||
abstract body(): JSX.Element |
||||
|
||||
onDeactivation () { |
||||
this.provider = null |
||||
} |
||||
|
||||
async init () { |
||||
this.nodeUrl = await ((): Promise<string> => { |
||||
return new Promise((resolve, reject) => { |
||||
const modalContent: AppModal = { |
||||
id: this.profile.name, |
||||
title: this.profile.displayName, |
||||
message: this.body(), |
||||
modalType: ModalTypes.prompt, |
||||
okLabel: 'OK', |
||||
cancelLabel: 'Cancel', |
||||
validationFn: (value) => { |
||||
if (!value) return { valid: false, message: "value is empty" } |
||||
if (value.startsWith('https://') || value.startsWith('http://')) { |
||||
return {
|
||||
valid: true,
|
||||
message: '' |
||||
} |
||||
} else { |
||||
return { |
||||
valid: false,
|
||||
message: 'the provided value should contain the protocol ( e.g starts with http:// or https:// )' |
||||
} |
||||
} |
||||
}, |
||||
okFn: (value: string) => { |
||||
setTimeout(() => resolve(value), 0) |
||||
}, |
||||
cancelFn: () => { |
||||
setTimeout(() => reject(new Error('Canceled')), 0) |
||||
}, |
||||
hideFn: () => { |
||||
setTimeout(() => reject(new Error('Hide')), 0) |
||||
}, |
||||
defaultValue: this.defaultUrl |
||||
} |
||||
this.call('notification', 'modal', modalContent) |
||||
}) |
||||
})() |
||||
this.provider = new ethers.providers.JsonRpcProvider(this.nodeUrl) |
||||
return { |
||||
nodeUrl: this.nodeUrl |
||||
} |
||||
} |
||||
|
||||
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')) |
||||
this.sendAsyncInternal(data, resolve, reject) |
||||
}) |
||||
} |
||||
|
||||
private async switchAway (showError) { |
||||
if (!this.provider) return |
||||
this.provider = null |
||||
this.connected = false |
||||
if (showError) { |
||||
const modalContent: AlertModal = { |
||||
id: this.profile.name, |
||||
title: this.profile.displayName, |
||||
message: `Error while connecting to the provider, provider not connected`, |
||||
} |
||||
this.call('notification', 'alert', modalContent) |
||||
} |
||||
await this.call('udapp', 'setEnvironmentMode', { context: 'vm-merge'}) |
||||
return |
||||
} |
||||
|
||||
private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise<void> { |
||||
if (this.provider) { |
||||
try { |
||||
const result = await this.provider.send(data.method, data.params) |
||||
resolve({ jsonrpc: '2.0', result, id: data.id }) |
||||
} catch (error) { |
||||
if (error && error.message && error.message.includes('net_version') && error.message.includes('SERVER_ERROR')) { |
||||
this.switchAway(true) |
||||
} |
||||
reject(error) |
||||
} |
||||
} else { |
||||
const result = data.method === 'net_listening' ? 'canceled' : [] |
||||
resolve({ jsonrpc: '2.0', result: result, id: data.id }) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { InjectedProvider } from './injected-provider' |
||||
|
||||
const profile = { |
||||
name: 'injected', |
||||
displayName: 'Injected Provider', |
||||
kind: 'provider', |
||||
description: 'injected Provider', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
} |
||||
|
||||
export class BasicInjectedProvider extends InjectedProvider {
|
||||
|
||||
constructor () { |
||||
super(profile) |
||||
} |
||||
} |
@ -0,0 +1,106 @@ |
||||
import React, { useRef } from 'react' // eslint-disable-line
|
||||
import * as packageJson from '../../../../../package.json' |
||||
import { AppModal, ModalTypes } from '@remix-ui/app' |
||||
import { BasicVMProvider } from './vm-provider' |
||||
import { Hardfork } from '@ethereumjs/common' |
||||
|
||||
export class CustomForkVMProvider extends BasicVMProvider { |
||||
nodeUrl: string |
||||
blockNumber: number | 'latest' |
||||
inputs: any |
||||
|
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-custom-fork', |
||||
displayName: 'Custom fork - Remix VM', |
||||
kind: 'provider', |
||||
description: 'Custom fork - Remix VM', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = '' |
||||
this.nodeUrl = '' |
||||
this.blockNumber = 'latest' |
||||
this.inputs = {} |
||||
} |
||||
|
||||
async init () { |
||||
const body = () => { |
||||
return <div> |
||||
<span>Please provide information about the custom fork. If the node URL is not provided, the VM will start with an empty state.</span> |
||||
<div> |
||||
<label className="mt-3 mb-1">Node URL</label> |
||||
<input data-id="CustomForkNodeUrl" name="nodeUrl" type="text" className="border form-control border-right-0" /> |
||||
</div> |
||||
<div> |
||||
<label className="mt-3 mb-1">Block number (or "latest")</label> |
||||
<input data-id="CustomForkBlockNumber" name="blockNumber" type="text" defaultValue="latest" placeholder='block number or "latest"' className="border form-control border-right-0" /> |
||||
</div> |
||||
<div> |
||||
<label className="mt-3 mb-1">EVM</label> |
||||
<select data-id="CustomForkEvmType" name="evmType" className="border form-control border-right-0"> |
||||
{Object.keys(Hardfork).map((value, index) => { |
||||
return <option value={Hardfork[value]} key={index}>{value}</option> |
||||
})}
|
||||
</select> |
||||
</div> |
||||
</div> |
||||
}
|
||||
const result = await ((): Promise<any> => { |
||||
return new Promise((resolve, reject) => { |
||||
const modalContent: AppModal = { |
||||
id: this.profile.name, |
||||
title: this.profile.displayName, |
||||
message: body(), |
||||
validationFn: (data: any) => { |
||||
if(data.nodeUrl !== '' && !data.nodeUrl.startsWith("http")) { |
||||
return { |
||||
valid: false, |
||||
message: 'node URL should be a valid URL' |
||||
} |
||||
} |
||||
if (data.blockNumber !== 'latest' && isNaN(data.blockNumber)) { |
||||
return { |
||||
valid: false, |
||||
message: 'blockNumber should be a number or "latest"' |
||||
} |
||||
} |
||||
return { |
||||
valid: true, |
||||
message: '' |
||||
} |
||||
}, |
||||
modalType: ModalTypes.form, |
||||
okLabel: 'Connect', |
||||
cancelLabel: 'Cancel', |
||||
okFn: (value: string) => { |
||||
setTimeout(() => resolve(value), 0) |
||||
}, |
||||
cancelFn: () => { |
||||
setTimeout(() => reject(new Error('Canceled')), 0) |
||||
}, |
||||
hideFn: () => { |
||||
setTimeout(() => reject(new Error('Hide')), 0) |
||||
} |
||||
} |
||||
return this.call('notification', 'modal', modalContent) |
||||
}) |
||||
})() |
||||
this.fork = result.evmType |
||||
this.nodeUrl = result.nodeUrl |
||||
if (this.nodeUrl) { |
||||
const block = result.blockNumber |
||||
this.blockNumber = block === 'latest' ? 'latest' : parseInt(block) |
||||
} else { |
||||
this.nodeUrl = undefined |
||||
this.blockNumber = undefined |
||||
} |
||||
|
||||
return { |
||||
'fork': this.fork, |
||||
'nodeUrl': this.nodeUrl, |
||||
'blockNumber': this.blockNumber |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { BasicVMProvider } from './vm-provider' |
||||
|
||||
export class GoerliForkVMProvider extends BasicVMProvider { |
||||
nodeUrl: string |
||||
blockNumber: number | 'latest' |
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-goerli-fork', |
||||
displayName: 'Goerli fork - Remix VM (London)', |
||||
kind: 'provider', |
||||
description: 'Remix VM (London)', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = 'merge' |
||||
this.nodeUrl = 'https://remix-sepolia.ethdevops.io' |
||||
this.blockNumber = 'latest' |
||||
} |
||||
|
||||
async init () { |
||||
return { |
||||
'fork': this.fork, |
||||
'nodeUrl': this.nodeUrl, |
||||
'blockNumber': this.blockNumber |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
import { InjectedProvider } from './injected-provider' |
||||
|
||||
export class InjectedL2Provider extends InjectedProvider {
|
||||
chainName: string |
||||
chainId: string |
||||
rpcUrls: Array<string> |
||||
|
||||
constructor (profile: any, chainName: string, chainId: string, rpcUrls: Array<string>) { |
||||
super(profile) |
||||
this.chainName = chainName |
||||
this.chainId = chainId |
||||
this.rpcUrls = rpcUrls |
||||
} |
||||
|
||||
async init () { |
||||
await super.init() |
||||
if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addL2Network(this.chainName, this.chainId, this.rpcUrls) |
||||
else |
||||
throw new Error('Cannot add the L2 network to main injected provider') |
||||
return {} |
||||
} |
||||
} |
||||
|
||||
export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array<string>) => { |
||||
try { |
||||
await (window as any).ethereum.request({ |
||||
method: 'wallet_switchEthereumChain', |
||||
params: [{ chainId: chainId }], |
||||
}); |
||||
} catch (switchError) { |
||||
// This error code indicates that the chain has not been added to MetaMask.
|
||||
if (switchError.code === 4902) { |
||||
try { |
||||
await (window as any).ethereum.request({ |
||||
method: 'wallet_addEthereumChain', |
||||
params: [ |
||||
{ |
||||
chainId: chainId, |
||||
chainName: chainName, |
||||
rpcUrls: rpcUrls, |
||||
}, |
||||
], |
||||
}); |
||||
|
||||
await (window as any).ethereum.request({ |
||||
method: 'wallet_switchEthereumChain', |
||||
params: [{ chainId: chainId }], |
||||
}); |
||||
} catch (addError) { |
||||
// handle "add" error
|
||||
} |
||||
} |
||||
// handle other "switch" errors
|
||||
} |
||||
} |
@ -1,21 +1,18 @@ |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { InjectedProvider } from './injected-provider' |
||||
import { InjectedL2Provider } from './injected-L2-provider' |
||||
|
||||
const profile = { |
||||
name: 'injected-arbitrum-one-provider', |
||||
displayName: 'Injected Arbitrum One Provider', |
||||
kind: 'provider', |
||||
description: 'injected Arbitrum One Provider', |
||||
methods: ['sendAsync'], |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
} |
||||
|
||||
export class InjectedArbitrumOneProvider extends InjectedProvider { |
||||
export class InjectedArbitrumOneProvider extends InjectedL2Provider { |
||||
|
||||
constructor () { |
||||
super(profile) |
||||
this.chainName = 'Arbitrum One' |
||||
this.chainId = '0xa4b1' |
||||
this.rpcUrls = ['https://arb1.arbitrum.io/rpc'] |
||||
super(profile, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc']) |
||||
} |
||||
} |
@ -1,21 +1,18 @@ |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { InjectedProvider } from './injected-provider' |
||||
import { InjectedL2Provider } from './injected-L2-provider' |
||||
|
||||
const profile = { |
||||
name: 'injected-optimism-provider', |
||||
displayName: 'Injected Optimism Provider', |
||||
kind: 'provider', |
||||
description: 'injected Optimism Provider', |
||||
methods: ['sendAsync'], |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
} |
||||
|
||||
export class Injected0ptimismProvider extends InjectedProvider { |
||||
export class Injected0ptimismProvider extends InjectedL2Provider { |
||||
|
||||
constructor () { |
||||
super(profile) |
||||
this.chainName = 'Optimism' |
||||
this.chainId = '0xa' |
||||
this.rpcUrls = ['https://mainnet.optimism.io'] |
||||
super(profile, 'Optimism', '0xa', ['https://mainnet.optimism.io']) |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { BasicVMProvider } from './vm-provider' |
||||
|
||||
export class MainnetForkVMProvider extends BasicVMProvider { |
||||
nodeUrl: string |
||||
blockNumber: number | 'latest' |
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-mainnet-fork', |
||||
displayName: 'Mainet fork -Remix VM (London)', |
||||
kind: 'provider', |
||||
description: 'Remix VM (London)', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = 'london' |
||||
this.nodeUrl = 'https://rpc.archivenode.io/e50zmkroshle2e2e50zm0044i7ao04ym' |
||||
this.blockNumber = 'latest' |
||||
} |
||||
|
||||
async init () { |
||||
return { |
||||
'fork': this.fork, |
||||
'nodeUrl': this.nodeUrl, |
||||
'blockNumber': this.blockNumber |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
import * as packageJson from '../../../../../package.json' |
||||
import { BasicVMProvider } from './vm-provider' |
||||
|
||||
export class SepoliaForkVMProvider extends BasicVMProvider { |
||||
nodeUrl: string |
||||
blockNumber: number | 'latest' |
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-sepolia-fork', |
||||
displayName: 'Sepolia fork - Remix VM (London)', |
||||
kind: 'provider', |
||||
description: 'Remix VM (London)', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = 'merge' |
||||
this.nodeUrl = 'https://remix-sepolia.ethdevops.io' |
||||
this.blockNumber = 'latest' |
||||
} |
||||
|
||||
async init () { |
||||
return { |
||||
'fork': this.fork, |
||||
'nodeUrl': this.nodeUrl, |
||||
'blockNumber': this.blockNumber |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,88 @@ |
||||
import React from 'react' // eslint-disable-line
|
||||
import * as packageJson from '../../../../../package.json' |
||||
import { JsonDataRequest, RejectRequest, SuccessRequest } from '../providers/abstract-provider' |
||||
import { Plugin } from '@remixproject/engine' |
||||
import { IProvider } from './abstract-provider' |
||||
|
||||
export class BasicVMProvider extends Plugin implements IProvider { |
||||
blockchain |
||||
fork: string |
||||
options: { [id: string] : any } = {} |
||||
constructor (profile, blockchain) { |
||||
super(profile) |
||||
this.blockchain = blockchain |
||||
this.fork = '' |
||||
} |
||||
|
||||
async init (): Promise<{ [id: string] : any }> { return {} } |
||||
|
||||
body (): JSX.Element { |
||||
return ( |
||||
<div></div> |
||||
) |
||||
} |
||||
|
||||
sendAsync (data: JsonDataRequest): Promise<any> { |
||||
return new Promise((resolve, reject) => { |
||||
this.sendAsyncInternal(data, resolve, reject) |
||||
}) |
||||
} |
||||
|
||||
private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise<void> { |
||||
try { |
||||
await this.blockchain.providers.vm.provider.sendAsync(data, (error, result) => { |
||||
if (error) return reject(error) |
||||
else { |
||||
resolve({ jsonrpc: '2.0', result, id: data.id }) |
||||
} |
||||
})
|
||||
} catch (error) { |
||||
reject(error) |
||||
} |
||||
} |
||||
} |
||||
|
||||
export class MergeVMProvider extends BasicVMProvider { |
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-merge', |
||||
displayName: 'Remix VM (Merge)', |
||||
kind: 'provider', |
||||
description: 'Remix VM (Merge)', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = 'merge' |
||||
} |
||||
} |
||||
|
||||
export class LondonVMProvider extends BasicVMProvider { |
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-london', |
||||
displayName: 'Remix VM (London)', |
||||
kind: 'provider', |
||||
description: 'Remix VM (London)', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = 'london' |
||||
} |
||||
} |
||||
|
||||
export class BerlinVMProvider extends BasicVMProvider { |
||||
constructor (blockchain) { |
||||
super({ |
||||
name: 'vm-berlin', |
||||
displayName: 'Remix VM (Berlin)', |
||||
kind: 'provider', |
||||
description: 'Remix VM (Berlin)', |
||||
methods: ['sendAsync', 'init'], |
||||
version: packageJson.version |
||||
}, blockchain) |
||||
this.blockchain = blockchain |
||||
this.fork = 'berlin' |
||||
} |
||||
} |
@ -1,157 +0,0 @@ |
||||
import { Plugin } from '@remixproject/engine' |
||||
import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app' |
||||
import { Blockchain } from '../../blockchain/blockchain' |
||||
import { ethers } from 'ethers' |
||||
|
||||
export type JsonDataRequest = { |
||||
id: number, |
||||
jsonrpc: string // version
|
||||
method: string, |
||||
params: Array<any>, |
||||
} |
||||
|
||||
export type JsonDataResult = { |
||||
id: number, |
||||
jsonrpc: string // version
|
||||
result: any |
||||
} |
||||
|
||||
export type RejectRequest = (error: Error) => void |
||||
export type SuccessRequest = (data: JsonDataResult) => void |
||||
|
||||
export abstract class AbstractProvider extends Plugin { |
||||
provider: ethers.providers.JsonRpcProvider |
||||
blocked: boolean |
||||
blockchain: Blockchain |
||||
defaultUrl: string |
||||
connected: boolean |
||||
|
||||
constructor (profile, blockchain, defaultUrl) { |
||||
super(profile) |
||||
this.defaultUrl = defaultUrl |
||||
this.provider = null |
||||
this.blocked = false // used to block any call when trying to recover after a failed connection.
|
||||
this.connected = false |
||||
this.blockchain = blockchain |
||||
} |
||||
|
||||
abstract body(): JSX.Element |
||||
|
||||
onDeactivation () { |
||||
this.provider = null |
||||
this.blocked = false |
||||
} |
||||
|
||||
sendAsync (data: JsonDataRequest): Promise<any> { |
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => { |
||||
if (this.blocked) return reject(new Error('provider unable to connect')) |
||||
// If provider is not set, allow to open modal only when provider is trying to connect
|
||||
if (!this.provider) { |
||||
let value: string |
||||
try { |
||||
value = await ((): Promise<string> => { |
||||
return new Promise((resolve, reject) => { |
||||
const modalContent: AppModal = { |
||||
id: this.profile.name, |
||||
title: this.profile.displayName, |
||||
message: this.body(), |
||||
modalType: ModalTypes.prompt, |
||||
okLabel: 'OK', |
||||
cancelLabel: 'Cancel', |
||||
validationFn: (value) => { |
||||
if (!value) return { valid: false, message: "value is empty" } |
||||
if (value.startsWith('https://') || value.startsWith('http://')) { |
||||
return {
|
||||
valid: true,
|
||||
message: '' |
||||
} |
||||
} else { |
||||
return { |
||||
valid: false,
|
||||
message: 'the provided value should contain the protocol ( e.g starts with http:// or https:// )' |
||||
} |
||||
} |
||||
}, |
||||
okFn: (value: string) => { |
||||
setTimeout(() => resolve(value), 0) |
||||
}, |
||||
cancelFn: () => { |
||||
setTimeout(() => reject(new Error('Canceled')), 0) |
||||
}, |
||||
hideFn: () => { |
||||
setTimeout(() => reject(new Error('Hide')), 0) |
||||
}, |
||||
defaultValue: this.defaultUrl |
||||
} |
||||
this.call('notification', 'modal', modalContent) |
||||
}) |
||||
})() |
||||
} catch (e) { |
||||
// the modal has been canceled/hide
|
||||
const result = data.method === 'net_listening' ? 'canceled' : [] |
||||
resolve({ jsonrpc: '2.0', result: result, id: data.id }) |
||||
this.switchAway(false) |
||||
return |
||||
} |
||||
this.provider = new ethers.providers.JsonRpcProvider(value) |
||||
try { |
||||
setTimeout(() => { |
||||
if (!this.connected) { |
||||
this.switchAway(true) |
||||
reject('Unable to connect') |
||||
} |
||||
}, 2000) |
||||
await this.provider.detectNetwork() // this throws if the network cannot be detected
|
||||
this.connected = true |
||||
} catch (e) { |
||||
this.switchAway(true) |
||||
reject('Unable to connect') |
||||
return |
||||
} |
||||
this.sendAsyncInternal(data, resolve, reject)
|
||||
} else { |
||||
this.sendAsyncInternal(data, resolve, reject) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
private async switchAway (showError) { |
||||
if (!this.provider) return |
||||
this.provider = null |
||||
this.blocked = true |
||||
this.connected = false |
||||
if (showError) { |
||||
const modalContent: AlertModal = { |
||||
id: this.profile.name, |
||||
title: this.profile.displayName, |
||||
message: `Error while connecting to the provider, provider not connected`, |
||||
} |
||||
this.call('notification', 'alert', modalContent) |
||||
} |
||||
await this.call('udapp', 'setEnvironmentMode', { context: 'vm', fork: 'london' }) |
||||
setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm
|
||||
return |
||||
} |
||||
|
||||
private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise<void> { |
||||
if (this.provider) { |
||||
// Check the case where current environment is VM on UI and it still sends RPC requests
|
||||
// This will be displayed on UI tooltip as 'cannot get account list: Environment Updated !!'
|
||||
if (this.blockchain.getProvider() !== this.profile.displayName && data.method !== 'net_listening') return reject(new Error('Environment Updated !!')) |
||||
|
||||
try { |
||||
const result = await this.provider.send(data.method, data.params) |
||||
resolve({ jsonrpc: '2.0', result, id: data.id }) |
||||
} catch (error) { |
||||
if (error && error.message && error.message.includes('net_version') && error.message.includes('SERVER_ERROR')) { |
||||
this.switchAway(true) |
||||
} |
||||
reject(error) |
||||
} |
||||
} else { |
||||
const result = data.method === 'net_listening' ? 'canceled' : [] |
||||
resolve({ jsonrpc: '2.0', result: result, id: data.id }) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,206 @@ |
||||
import { keccak224, keccak384, keccak256 as k256, keccak512 } from 'ethereum-cryptography/keccak' |
||||
const createHash = require('create-hash') |
||||
import { encode, Input } from 'rlp' |
||||
import { toBuffer, setLengthLeft, isHexString } from '@ethereumjs/util' |
||||
|
||||
/** |
||||
* Creates Keccak hash of a Buffer input |
||||
* @param a The input data (Buffer) |
||||
* @param bits (number = 256) The Keccak width |
||||
*/ |
||||
export const keccak = function(a: Buffer, bits: number = 256): Buffer { |
||||
assertIsBuffer(a) |
||||
switch (bits) { |
||||
case 224: { |
||||
return toBuffer(keccak224(a)) |
||||
} |
||||
case 256: { |
||||
return toBuffer(k256(a)) |
||||
} |
||||
case 384: { |
||||
return toBuffer(keccak384(a)) |
||||
} |
||||
case 512: { |
||||
return toBuffer(keccak512(a)) |
||||
} |
||||
default: { |
||||
throw new Error(`Invald algorithm: keccak${bits}`) |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates Keccak-256 hash of the input, alias for keccak(a, 256). |
||||
* @param a The input data (Buffer) |
||||
*/ |
||||
export const keccak256 = function(a: Buffer): Buffer { |
||||
return keccak(a) |
||||
} |
||||
|
||||
/** |
||||
* Creates Keccak hash of a utf-8 string input |
||||
* @param a The input data (String) |
||||
* @param bits (number = 256) The Keccak width |
||||
*/ |
||||
export const keccakFromString = function(a: string, bits: number = 256) { |
||||
assertIsString(a) |
||||
const buf = Buffer.from(a, 'utf8') |
||||
return keccak(buf, bits) |
||||
} |
||||
|
||||
/** |
||||
* Creates Keccak hash of an 0x-prefixed string input |
||||
* @param a The input data (String) |
||||
* @param bits (number = 256) The Keccak width |
||||
*/ |
||||
export const keccakFromHexString = function(a: string, bits: number = 256) { |
||||
assertIsHexString(a) |
||||
return keccak(toBuffer(a), bits) |
||||
} |
||||
|
||||
/** |
||||
* Creates Keccak hash of a number array input |
||||
* @param a The input data (number[]) |
||||
* @param bits (number = 256) The Keccak width |
||||
*/ |
||||
export const keccakFromArray = function(a: number[], bits: number = 256) { |
||||
assertIsArray(a) |
||||
return keccak(toBuffer(a), bits) |
||||
} |
||||
|
||||
/** |
||||
* Creates SHA256 hash of an input. |
||||
* @param a The input data (Buffer|Array|String) |
||||
*/ |
||||
const _sha256 = function(a: any): Buffer { |
||||
a = toBuffer(a) |
||||
return createHash('sha256') |
||||
.update(a) |
||||
.digest() |
||||
} |
||||
|
||||
/** |
||||
* Creates SHA256 hash of a Buffer input. |
||||
* @param a The input data (Buffer) |
||||
*/ |
||||
export const sha256 = function(a: Buffer): Buffer { |
||||
assertIsBuffer(a) |
||||
return _sha256(a) |
||||
} |
||||
|
||||
/** |
||||
* Creates SHA256 hash of a string input. |
||||
* @param a The input data (string) |
||||
*/ |
||||
export const sha256FromString = function(a: string): Buffer { |
||||
assertIsString(a) |
||||
return _sha256(a) |
||||
} |
||||
|
||||
/** |
||||
* Creates SHA256 hash of a number[] input. |
||||
* @param a The input data (number[]) |
||||
*/ |
||||
export const sha256FromArray = function(a: number[]): Buffer { |
||||
assertIsArray(a) |
||||
return _sha256(a) |
||||
} |
||||
|
||||
/** |
||||
* Creates RIPEMD160 hash of the input. |
||||
* @param a The input data (Buffer|Array|String|Number) |
||||
* @param padded Whether it should be padded to 256 bits or not |
||||
*/ |
||||
const _ripemd160 = function(a: any, padded: boolean): Buffer { |
||||
a = toBuffer(a) |
||||
const hash = createHash('rmd160') |
||||
.update(a) |
||||
.digest() |
||||
if (padded === true) { |
||||
return setLengthLeft(hash, 32) |
||||
} else { |
||||
return hash |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates RIPEMD160 hash of a Buffer input. |
||||
* @param a The input data (Buffer) |
||||
* @param padded Whether it should be padded to 256 bits or not |
||||
*/ |
||||
export const ripemd160 = function(a: Buffer, padded: boolean): Buffer { |
||||
assertIsBuffer(a) |
||||
return _ripemd160(a, padded) |
||||
} |
||||
|
||||
/** |
||||
* Creates RIPEMD160 hash of a string input. |
||||
* @param a The input data (String) |
||||
* @param padded Whether it should be padded to 256 bits or not |
||||
*/ |
||||
export const ripemd160FromString = function(a: string, padded: boolean): Buffer { |
||||
assertIsString(a) |
||||
return _ripemd160(a, padded) |
||||
} |
||||
|
||||
/** |
||||
* Creates RIPEMD160 hash of a number[] input. |
||||
* @param a The input data (number[]) |
||||
* @param padded Whether it should be padded to 256 bits or not |
||||
*/ |
||||
export const ripemd160FromArray = function(a: number[], padded: boolean): Buffer { |
||||
assertIsArray(a) |
||||
return _ripemd160(a, padded) |
||||
} |
||||
|
||||
/** |
||||
* Creates SHA-3 hash of the RLP encoded version of the input. |
||||
* @param a The input data |
||||
*/ |
||||
export const rlphash = function(a: Input): Buffer { |
||||
return keccak(encode(a)) |
||||
} |
||||
|
||||
/** |
||||
* Throws if a string is not hex prefixed |
||||
* @param {string} input string to check hex prefix of |
||||
*/ |
||||
export const assertIsHexString = function(input: string): void { |
||||
if (!isHexString(input)) { |
||||
const msg = `This method only supports 0x-prefixed hex strings but input was: ${input}` |
||||
throw new Error(msg) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Throws if input is not a buffer |
||||
* @param {Buffer} input value to check |
||||
*/ |
||||
export const assertIsBuffer = function(input: Buffer): void { |
||||
if (!Buffer.isBuffer(input)) { |
||||
const msg = `This method only supports Buffer but input was: ${input}` |
||||
throw new Error(msg) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Throws if input is not an array |
||||
* @param {number[]} input value to check |
||||
*/ |
||||
export const assertIsArray = function(input: number[]): void { |
||||
if (!Array.isArray(input)) { |
||||
const msg = `This method only supports number arrays but input was: ${input}` |
||||
throw new Error(msg) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Throws if input is not a string |
||||
* @param {string} input value to check |
||||
*/ |
||||
export const assertIsString = function(input: string): void { |
||||
if (typeof input !== 'string') { |
||||
const msg = `This method only supports strings but input was: ${input}` |
||||
throw new Error(msg) |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue