@ -1,4 +1,3 @@
import React from 'react' // eslint-disable-line
import Web3 from 'web3'
import { Plugin } from '@remixproject/engine'
@ -12,36 +11,58 @@ import { InjectedProvider } from './providers/injected'
import { NodeProvider } from './providers/node'
import { execution , EventManager , helpers } from '@remix-project/remix-lib'
import { etherScanLink } from './helper'
import { logBuilder , cancelUpgradeMsg , cancelProxyMsg , addressToString } from "@remix-ui/helper"
const { txFormat , txExecution , typeConversion , txListener : Txlistener , TxRunner , TxRunnerWeb3 , txHelper } = execution
import {
logBuilder ,
cancelUpgradeMsg ,
cancelProxyMsg ,
addressToString
} from '@remix-ui/helper'
const {
txFormat ,
txExecution ,
typeConversion ,
txListener : Txlistener ,
TxRunner ,
TxRunnerWeb3 ,
txHelper
} = execution
const { txResultHelper } = helpers
const { resultToRemixTx } = txResultHelper
import * as packageJson from '../../../../package.json'
const _paq = window . _paq = window . _paq || [ ] //eslint-disable-line
const _paq = ( window . _paq = window . _paq || [ ] ) //eslint-disable-line
const profile = {
name : 'blockchain' ,
displayName : 'Blockchain' ,
description : 'Blockchain - Logic' ,
methods : [ 'getCode' , 'getTransactionReceipt' , 'addProvider' , 'removeProvider' , 'getCurrentFork' , 'getAccounts' , 'web3VM' , 'getProvider' ] ,
methods : [
'getCode' ,
'getTransactionReceipt' ,
'addProvider' ,
'removeProvider' ,
'getCurrentFork' ,
'getAccounts' ,
'web3VM' ,
'getProvider'
] ,
version : packageJson.version
}
export type TransactionContextAPI = {
getAddress : ( cb : ( error : Error , result : string ) = > void ) = > void ,
getValue : ( cb : ( error : Error , result : string ) = > void ) = > void ,
getAddress : ( cb : ( error : Error , result : string ) = > void ) = > void
getValue : ( cb : ( error : Error , result : string ) = > void ) = > void
getGasLimit : ( cb : ( error : Error , result : string ) = > void ) = > void
}
// see TxRunner.ts in remix-lib
export type Transaction = {
from : string ,
to : string ,
value : string ,
data : string ,
gasLimit : number ,
useCall : boolean ,
from : string
to : string
value : string
data : string
gasLimit : number
useCall : boolean
timestamp? : number
}
@ -55,7 +76,7 @@ export class Blockchain extends Plugin {
networkcallid : number
networkStatus : {
network : {
name : string ,
name : string
id : string
}
error? : string
@ -72,16 +93,24 @@ export class Blockchain extends Plugin {
this . events = new EventEmitter ( )
this . config = config
const web3Runner = new TxRunnerWeb3 ( {
const web3Runner = new TxRunnerWeb3 (
{
config : this.config ,
detectNetwork : ( cb ) = > {
this . executionContext . detectNetwork ( cb )
} ,
isVM : ( ) = > { return this . executionContext . isVM ( ) } ,
isVM : ( ) = > {
return this . executionContext . isVM ( )
} ,
personalMode : ( ) = > {
return this . getProvider ( ) === 'web3' ? this . config . get ( 'settings/personal-mode' ) : false
return this . getProvider ( ) === 'web3'
? this . config . get ( 'settings/personal-mode' )
: false
}
} , _ = > this . executionContext . web3 ( ) , _ = > this . executionContext . currentblockGasLimit ( ) )
} ,
( _ ) = > this . executionContext . web3 ( ) ,
( _ ) = > this . executionContext . currentblockGasLimit ( )
)
this . txRunner = new TxRunner ( web3Runner , { } )
this . networkcallid = 0
@ -189,33 +218,86 @@ export class Blockchain extends Plugin {
} )
}
deployContractAndLibraries ( selectedContract , args , contractMetadata , compilerContracts , callbacks , confirmationCb ) {
deployContractAndLibraries (
selectedContract ,
args ,
contractMetadata ,
compilerContracts ,
callbacks ,
confirmationCb
) {
const { continueCb , promptCb , statusCb , finalCb } = callbacks
const constructor = selectedContract . getConstructorInterface ( )
txFormat . buildData ( selectedContract . name , selectedContract . object , compilerContracts , true , constructor , args , ( error , data ) = > {
txFormat . buildData (
selectedContract . name ,
selectedContract . object ,
compilerContracts ,
true ,
constructor ,
args ,
( error , data ) = > {
if ( error ) {
return statusCb ( ` creation of ${ selectedContract . name } errored: ${ error . message ? error.message : error } ` )
return statusCb (
` creation of ${ selectedContract . name } errored: ${
error . message ? error.message : error
} `
)
}
statusCb ( ` creation of ${ selectedContract . name } pending... ` )
this . createContract ( selectedContract , data , continueCb , promptCb , confirmationCb , finalCb )
} , statusCb , ( data , runTxCallback ) = > {
this . createContract (
selectedContract ,
data ,
continueCb ,
promptCb ,
confirmationCb ,
finalCb
)
} ,
statusCb ,
( data , runTxCallback ) = > {
// called for libraries deployment
this . runTx ( data , confirmationCb , continueCb , promptCb , runTxCallback )
} )
}
)
}
deployContractWithLibrary ( selectedContract , args , contractMetadata , compilerContracts , callbacks , confirmationCb ) {
deployContractWithLibrary (
selectedContract ,
args ,
contractMetadata ,
compilerContracts ,
callbacks ,
confirmationCb
) {
const { continueCb , promptCb , statusCb , finalCb } = callbacks
const constructor = selectedContract . getConstructorInterface ( )
txFormat . encodeConstructorCallAndLinkLibraries ( selectedContract . object , args , constructor , contractMetadata . linkReferences , selectedContract . bytecodeLinkReferences , ( error , data ) = > {
txFormat . encodeConstructorCallAndLinkLibraries (
selectedContract . object ,
args ,
constructor ,
contractMetadata . linkReferences ,
selectedContract . bytecodeLinkReferences ,
( error , data ) = > {
if ( error ) {
return statusCb ( ` creation of ${ selectedContract . name } errored: ${ error . message ? error.message : error } ` )
return statusCb (
` creation of ${ selectedContract . name } errored: ${
error . message ? error.message : error
} `
)
}
statusCb ( ` creation of ${ selectedContract . name } pending... ` )
this . createContract ( selectedContract , data , continueCb , promptCb , confirmationCb , finalCb )
} )
this . createContract (
selectedContract ,
data ,
continueCb ,
promptCb ,
confirmationCb ,
finalCb
)
}
)
}
async deployProxy ( proxyData , implementationContractObject ) {
@ -229,11 +311,21 @@ export class Blockchain extends Plugin {
cancelLabel : 'Cancel' ,
okFn : ( ) = > {
this . runProxyTx ( proxyData , implementationContractObject )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Deploy With Proxy' , 'modal ok confirmation' ] )
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Deploy With Proxy' ,
'modal ok confirmation'
] )
} ,
cancelFn : ( ) = > {
this . call ( 'notification' , 'toast' , cancelProxyMsg ( ) )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Deploy With Proxy' , 'cancel proxy deployment' ] )
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Deploy With Proxy' ,
'cancel proxy deployment'
] )
} ,
hideFn : ( ) = > null
}
@ -243,30 +335,70 @@ export class Blockchain extends Plugin {
async runProxyTx ( proxyData , implementationContractObject ) {
const args = { useCall : false , data : proxyData }
let networkInfo
const confirmationCb = ( network , tx , gasEstimation , continueTxExecution , cancelCb ) = > {
const confirmationCb = (
network ,
tx ,
gasEstimation ,
continueTxExecution ,
cancelCb
) = > {
networkInfo = network
// continue using original authorization given by user
continueTxExecution ( null )
}
const continueCb = ( error , continueTxExecution , cancelCb ) = > { continueTxExecution ( ) }
const promptCb = ( okCb , cancelCb ) = > { okCb ( ) }
const continueCb = ( error , continueTxExecution , cancelCb ) = > {
continueTxExecution ( )
}
const promptCb = ( okCb , cancelCb ) = > {
okCb ( )
}
const finalCb = async ( error , txResult , address , returnValue ) = > {
if ( error ) {
const log = logBuilder ( error )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Deploy With Proxy' , 'Proxy deployment failed: ' + error ] )
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Deploy With Proxy' ,
'Proxy deployment failed: ' + error
] )
return this . call ( 'terminal' , 'logHtml' , log )
}
await this . saveDeployedContractStorageLayout ( implementationContractObject , address , networkInfo )
this . events . emit ( 'newProxyDeployment' , address , new Date ( ) . toISOString ( ) , implementationContractObject . contractName )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Deploy With Proxy' , 'Proxy deployment successful' ] )
this . call ( 'udapp' , 'addInstance' , addressToString ( address ) , implementationContractObject . abi , implementationContractObject . name )
await this . saveDeployedContractStorageLayout (
implementationContractObject ,
address ,
networkInfo
)
this . events . emit (
'newProxyDeployment' ,
address ,
new Date ( ) . toISOString ( ) ,
implementationContractObject . contractName
)
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Deploy With Proxy' ,
'Proxy deployment successful'
] )
this . call (
'udapp' ,
'addInstance' ,
addressToString ( address ) ,
implementationContractObject . abi ,
implementationContractObject . name
)
}
this . runTx ( args , confirmationCb , continueCb , promptCb , finalCb )
}
async upgradeProxy ( proxyAddress , newImplAddress , data , newImplementationContractObject ) {
async upgradeProxy (
proxyAddress ,
newImplAddress ,
data ,
newImplementationContractObject
) {
const upgradeModal = {
id : 'confirmProxyDeployment' ,
title : 'Confirm Update Proxy (ERC1967)' ,
@ -276,11 +408,21 @@ export class Blockchain extends Plugin {
cancelLabel : 'Cancel' ,
okFn : ( ) = > {
this . runUpgradeTx ( proxyAddress , data , newImplementationContractObject )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Upgrade With Proxy' , 'proxy upgrade confirmation click' ] )
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Upgrade With Proxy' ,
'proxy upgrade confirmation click'
] )
} ,
cancelFn : ( ) = > {
this . call ( 'notification' , 'toast' , cancelUpgradeMsg ( ) )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Upgrade With Proxy' , 'proxy upgrade cancel click' ] )
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Upgrade With Proxy' ,
'proxy upgrade cancel click'
] )
} ,
hideFn : ( ) = > null
}
@ -290,42 +432,96 @@ export class Blockchain extends Plugin {
async runUpgradeTx ( proxyAddress , data , newImplementationContractObject ) {
const args = { useCall : false , data , to : proxyAddress }
let networkInfo
const confirmationCb = ( network , tx , gasEstimation , continueTxExecution , cancelCb ) = > {
const confirmationCb = (
network ,
tx ,
gasEstimation ,
continueTxExecution ,
cancelCb
) = > {
// continue using original authorization given by user
networkInfo = network
continueTxExecution ( null )
}
const continueCb = ( error , continueTxExecution , cancelCb ) = > { continueTxExecution ( ) }
const promptCb = ( okCb , cancelCb ) = > { okCb ( ) }
const continueCb = ( error , continueTxExecution , cancelCb ) = > {
continueTxExecution ( )
}
const promptCb = ( okCb , cancelCb ) = > {
okCb ( )
}
const finalCb = async ( error , txResult , address , returnValue ) = > {
if ( error ) {
const log = logBuilder ( error )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Upgrade With Proxy' , 'Upgrade failed' ] )
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Upgrade With Proxy' ,
'Upgrade failed'
] )
return this . call ( 'terminal' , 'logHtml' , log )
}
await this . saveDeployedContractStorageLayout ( newImplementationContractObject , proxyAddress , networkInfo )
_paq . push ( [ 'trackEvent' , 'blockchain' , 'Upgrade With Proxy' , 'Upgrade Successful' ] )
this . call ( 'udapp' , 'addInstance' , addressToString ( proxyAddress ) , newImplementationContractObject . abi , newImplementationContractObject . name )
await this . saveDeployedContractStorageLayout (
newImplementationContractObject ,
proxyAddress ,
networkInfo
)
_paq . push ( [
'trackEvent' ,
'blockchain' ,
'Upgrade With Proxy' ,
'Upgrade Successful'
] )
this . call (
'udapp' ,
'addInstance' ,
addressToString ( proxyAddress ) ,
newImplementationContractObject . abi ,
newImplementationContractObject . name
)
}
this . runTx ( args , confirmationCb , continueCb , promptCb , finalCb )
}
async saveDeployedContractStorageLayout ( contractObject , proxyAddress , networkInfo ) {
async saveDeployedContractStorageLayout (
contractObject ,
proxyAddress ,
networkInfo
) {
const { contractName , implementationAddress } = contractObject
const networkName = networkInfo . name === 'custom' ? networkInfo . name + '-' + networkInfo.id : networkInfo.name
const hasPreviousDeploys = await this . call ( 'fileManager' , 'exists' , ` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json ` )
const networkName =
networkInfo . name === 'custom'
? networkInfo . name + '-' + networkInfo . id
: networkInfo . name
const hasPreviousDeploys = await this . call (
'fileManager' ,
'exists' ,
` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json `
)
// TODO: make deploys folder read only.
if ( hasPreviousDeploys ) {
const deployments = await this . call ( 'fileManager' , 'readFile' , ` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json ` )
const deployments = await this . call (
'fileManager' ,
'readFile' ,
` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json `
)
const parsedDeployments = JSON . parse ( deployments )
const proxyDeployment = parsedDeployments . deployments [ proxyAddress ]
if ( proxyDeployment ) {
const oldImplementationAddress = proxyDeployment . implementationAddress
const hasPreviousBuild = await this . call ( 'fileManager' , 'exists' , ` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ oldImplementationAddress } .json ` )
const hasPreviousBuild = await this . call (
'fileManager' ,
'exists' ,
` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ oldImplementationAddress } .json `
)
if ( hasPreviousBuild ) await this . call ( 'fileManager' , 'remove' , ` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ oldImplementationAddress } .json ` )
if ( hasPreviousBuild )
await this . call (
'fileManager' ,
'remove' ,
` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ oldImplementationAddress } .json `
)
}
parsedDeployments . deployments [ proxyAddress ] = {
date : new Date ( ) . toISOString ( ) ,
@ -335,17 +531,45 @@ export class Blockchain extends Plugin {
solcOutput : contractObject.compiler.data ,
solcInput : contractObject.compiler.source
}
await this . call ( 'fileManager' , 'writeFile' , ` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ implementationAddress } .json ` , JSON . stringify ( {
await this . call (
'fileManager' ,
'writeFile' ,
` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ implementationAddress } .json ` ,
JSON . stringify (
{
solcInput : contractObject.compiler.source ,
solcOutput : contractObject.compiler.data
} , null , 2 ) )
await this . call ( 'fileManager' , 'writeFile' , ` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json ` , JSON . stringify ( parsedDeployments , null , 2 ) )
} ,
null ,
2
)
)
await this . call (
'fileManager' ,
'writeFile' ,
` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json ` ,
JSON . stringify ( parsedDeployments , null , 2 )
)
} else {
await this . call ( 'fileManager' , 'writeFile' , ` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ implementationAddress } .json ` , JSON . stringify ( {
await this . call (
'fileManager' ,
'writeFile' ,
` .deploys/upgradeable-contracts/ ${ networkName } /solc- ${ implementationAddress } .json ` ,
JSON . stringify (
{
solcInput : contractObject.compiler.source ,
solcOutput : contractObject.compiler.data
} , null , 2 ) )
await this . call ( 'fileManager' , 'writeFile' , ` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json ` , JSON . stringify ( {
} ,
null ,
2
)
)
await this . call (
'fileManager' ,
'writeFile' ,
` .deploys/upgradeable-contracts/ ${ networkName } /UUPS.json ` ,
JSON . stringify (
{
id : networkInfo.id ,
network : networkInfo.name ,
deployments : {
@ -356,7 +580,11 @@ export class Blockchain extends Plugin {
implementationAddress : implementationAddress
}
}
} , null , 2 ) )
} ,
null ,
2
)
)
}
}
@ -378,20 +606,41 @@ export class Blockchain extends Plugin {
} )
}
createContract ( selectedContract , data , continueCb , promptCb , confirmationCb , finalCb ) {
createContract (
selectedContract ,
data ,
continueCb ,
promptCb ,
confirmationCb ,
finalCb
) {
if ( data ) {
data . contractName = selectedContract . name
data . linkReferences = selectedContract . bytecodeLinkReferences
data . contractABI = selectedContract . abi
}
this . runTx ( { data : data , useCall : false } , confirmationCb , continueCb , promptCb ,
this . runTx (
{ data : data , useCall : false } ,
confirmationCb ,
continueCb ,
promptCb ,
( error , txResult , address ) = > {
if ( error ) {
return finalCb ( ` creation of ${ selectedContract . name } errored: ${ error . message ? error.message : error } ` )
return finalCb (
` creation of ${ selectedContract . name } errored: ${
error . message ? error.message : error
} `
)
}
if ( txResult . receipt . status === false || txResult . receipt . status === '0x0' || txResult . receipt . status === 0 ) {
return finalCb ( ` creation of ${ selectedContract . name } errored: transaction execution failed ` )
if (
txResult . receipt . status === false ||
txResult . receipt . status === '0x0' ||
txResult . receipt . status === 0
) {
return finalCb (
` creation of ${ selectedContract . name } errored: transaction execution failed `
)
}
finalCb ( null , selectedContract , address )
}
@ -400,9 +649,14 @@ export class Blockchain extends Plugin {
determineGasPrice ( cb ) {
this . getCurrentProvider ( ) . getGasPrice ( ( error , gasPrice ) = > {
const warnMessage = ' Please fix this issue before sending any transaction. '
const warnMessage =
' Please fix this issue before sending any transaction. '
if ( error ) {
return cb ( 'Unable to retrieve the current network gas price.' + warnMessage + error )
return cb (
'Unable to retrieve the current network gas price.' +
warnMessage +
error
)
}
try {
const gasPriceValue = this . fromWei ( gasPrice , false , 'gwei' )
@ -432,7 +686,13 @@ export class Blockchain extends Plugin {
}
calculateFee ( gas , gasPrice , unit ? ) {
return Web3 . utils . toBN ( gas ) . mul ( Web3 . utils . toBN ( Web3 . utils . toWei ( gasPrice . toString ( 10 ) as string , unit || 'gwei' ) ) )
return Web3 . utils
. toBN ( gas )
. mul (
Web3 . utils . toBN (
Web3 . utils . toWei ( gasPrice . toString ( 10 ) as string , unit || 'gwei' )
)
)
}
determineGasFees ( tx ) {
@ -445,7 +705,8 @@ export class Blockchain extends Plugin {
txFeeText = ' ' + this . fromWei ( fee , false , 'ether' ) + ' Ether'
priceStatus = true
} catch ( e ) {
txFeeText = ' Please fix this issue before sending any transaction. ' + e . message
txFeeText =
' Please fix this issue before sending any transaction. ' + e . message
priceStatus = false
}
cb ( txFeeText , priceStatus )
@ -455,7 +716,13 @@ export class Blockchain extends Plugin {
}
changeExecutionContext ( context , confirmCb , infoCb , cb ) {
return this . executionContext . executionContextChange ( context , null , confirmCb , infoCb , cb )
return this . executionContext . executionContextChange (
context ,
null ,
confirmCb ,
infoCb ,
cb
)
}
detectNetwork ( cb ) {
@ -481,7 +748,7 @@ export class Blockchain extends Plugin {
isWeb3Provider() {
const isVM = this . executionContext . isVM ( )
const isInjected = this . getProvider ( ) === 'injected'
return ( ! isVM && ! isInjected )
return ! isVM && ! isInjected
}
isInjectedWeb3() {
@ -514,11 +781,35 @@ export class Blockchain extends Plugin {
return txlistener
}
runOrCallContractMethod ( contractName , contractAbi , funABI , contract , value , address , callType , lookupOnly , logMsg , logCallback , outputCb , confirmationCb , continueCb , promptCb ) {
runOrCallContractMethod (
contractName ,
contractAbi ,
funABI ,
contract ,
value ,
address ,
callType ,
lookupOnly ,
logMsg ,
logCallback ,
outputCb ,
confirmationCb ,
continueCb ,
promptCb
) {
// contractsDetails is used to resolve libraries
txFormat . buildData ( contractName , contractAbi , { } , false , funABI , callType , ( error , data ) = > {
txFormat . buildData (
contractName ,
contractAbi ,
{ } ,
false ,
funABI ,
callType ,
( error , data ) = > {
if ( error ) {
return logCallback ( ` ${ logMsg } errored: ${ error . message ? error.message : error } ` )
return logCallback (
` ${ logMsg } errored: ${ error . message ? error.message : error } `
)
}
if ( ! lookupOnly ) {
logCallback ( ` ${ logMsg } pending ... ` )
@ -532,31 +823,46 @@ export class Blockchain extends Plugin {
data . contractABI = contractAbi
data . contract = contract
}
const useCall = funABI . stateMutability === 'view' || funABI . stateMutability === 'pure'
this . runTx ( { to : address , data , useCall } , confirmationCb , continueCb , promptCb , ( error , txResult , _address , returnValue ) = > {
const useCall =
funABI . stateMutability === 'view' || funABI . stateMutability === 'pure'
this . runTx (
{ to : address , data , useCall } ,
confirmationCb ,
continueCb ,
promptCb ,
( error , txResult , _address , returnValue ) = > {
if ( error ) {
return logCallback ( ` ${ logMsg } errored: ${ error . message ? error.message : error } ` )
return logCallback (
` ${ logMsg } errored: ${ error . message ? error.message : error } `
)
}
if ( lookupOnly ) {
outputCb ( returnValue )
}
} )
}
)
} ,
( msg ) = > {
logCallback ( msg )
} ,
( data , runTxCallback ) = > {
// called for libraries deployment
this . runTx ( data , confirmationCb , runTxCallback , promptCb , ( ) = > { /* Do nothing. */ } )
this . runTx ( data , confirmationCb , runTxCallback , promptCb , ( ) = > {
/* Do nothing. */
} )
}
)
}
context() {
return ( this . executionContext . isVM ( ) ? 'memory' : 'blockchain' )
return this . executionContext . isVM ( ) ? 'memory' : 'blockchain'
}
// NOTE: the config is only needed because exectuionContext.init does
async resetAndInit ( config : Config , transactionContextAPI : TransactionContextAPI ) {
async resetAndInit (
config : Config ,
transactionContextAPI : TransactionContextAPI
) {
this . transactionContextAPI = transactionContextAPI
this . executionContext . init ( config )
this . executionContext . stopListenOnLastBlock ( )
@ -582,16 +888,24 @@ export class Blockchain extends Plugin {
async resetEnvironment() {
await this . getCurrentProvider ( ) . resetEnvironment ( )
// TODO: most params here can be refactored away in txRunner
const web3Runner = new TxRunnerWeb3 ( {
const web3Runner = new TxRunnerWeb3 (
{
config : this.config ,
detectNetwork : ( cb ) = > {
this . executionContext . detectNetwork ( cb )
} ,
isVM : ( ) = > { return this . executionContext . isVM ( ) } ,
isVM : ( ) = > {
return this . executionContext . isVM ( )
} ,
personalMode : ( ) = > {
return this . getProvider ( ) === 'web3' ? this . config . get ( 'settings/personal-mode' ) : false
return this . getProvider ( ) === 'web3'
? this . config . get ( 'settings/personal-mode' )
: false
}
} , _ = > this . executionContext . web3 ( ) , _ = > this . executionContext . currentblockGasLimit ( ) )
} ,
( _ ) = > this . executionContext . web3 ( ) ,
( _ ) = > this . executionContext . currentblockGasLimit ( )
)
web3Runner . event . register ( 'transactionBroadcasted' , ( txhash ) = > {
this . executionContext . detectNetwork ( ( error , network ) = > {
@ -600,10 +914,13 @@ export class Blockchain extends Plugin {
const viewEtherScanLink = etherScanLink ( network . name , txhash )
if ( viewEtherScanLink ) {
this . call ( 'terminal' , 'logHtml' ,
( < a href = { etherScanLink ( network . name , txhash ) } target = "_blank" >
this . call (
'terminal' ,
'logHtml' ,
< a href = { etherScanLink ( network . name , txhash ) } target = "_blank" >
view on etherscan
< / a > ) )
< / a >
)
}
} )
} )
@ -616,7 +933,9 @@ export class Blockchain extends Plugin {
* /
createVMAccount ( newAccount ) {
if ( ! this . executionContext . isVM ( ) ) {
throw new Error ( 'plugin API does not allow creating a new account through web3 connection. Only vm mode is allowed' )
throw new Error (
'plugin API does not allow creating a new account through web3 connection. Only vm mode is allowed'
)
}
return ( this . providers . vm as VMProvider ) . createVMAccount ( newAccount )
}
@ -653,22 +972,36 @@ export class Blockchain extends Plugin {
this . executionContext . detectNetwork ( ( error , network ) = > {
if ( error ) return reject ( error )
if ( network . name === 'Main' && network . id === '1' ) {
return reject ( new Error ( 'It is not allowed to make this action against mainnet' ) )
return reject (
new Error ( 'It is not allowed to make this action against mainnet' )
)
}
this . txRunner . rawRun (
tx ,
( network , tx , gasEstimation , continueTxExecution , cancelCb ) = > { continueTxExecution ( ) } ,
( error , continueTxExecution , cancelCb ) = > { if ( error ) { reject ( error ) } else { continueTxExecution ( ) } } ,
( okCb , cancelCb ) = > { okCb ( ) } ,
( network , tx , gasEstimation , continueTxExecution , cancelCb ) = > {
continueTxExecution ( )
} ,
( error , continueTxExecution , cancelCb ) = > {
if ( error ) {
reject ( error )
} else {
continueTxExecution ( )
}
} ,
( okCb , cancelCb ) = > {
okCb ( )
} ,
async ( error , result ) = > {
if ( error ) return reject ( error )
try {
if ( this . executionContext . isVM ( ) ) {
const execResult = await this . web3 ( ) . eth . getExecutionResultFromSimulator ( result . transactionHash )
const execResult =
await this . web3 ( ) . eth . getExecutionResultFromSimulator (
result . transactionHash
)
resolve ( resultToRemixTx ( result , execResult ) )
} else
resolve ( resultToRemixTx ( result ) )
} else resolve ( resultToRemixTx ( result ) )
} catch ( e ) {
reject ( e )
}
@ -712,7 +1045,10 @@ export class Blockchain extends Plugin {
if ( this . transactionContextAPI . getAddress ) {
return this . transactionContextAPI . getAddress ( function ( err , address ) {
if ( err ) return reject ( err )
if ( ! address ) return reject ( '"from" is not defined. Please make sure an account is selected. If you are using a public node, it is likely that no account will be provided. In that case, add the public node to your injected provider (type Metamask) and use injected provider in Remix.' )
if ( ! address )
return reject (
'"from" is not defined. Please make sure an account is selected. If you are using a public node, it is likely that no account will be provided. In that case, add the public node to your injected provider (type Metamask) and use injected provider in Remix.'
)
return resolve ( address )
} )
}
@ -721,7 +1057,10 @@ export class Blockchain extends Plugin {
const address = accounts [ 0 ]
if ( ! address ) return reject ( 'No accounts available' )
if ( this . executionContext . isVM ( ) && ! this . providers . vm . RemixSimulatorProvider . Accounts . accounts [ address ] ) {
if (
this . executionContext . isVM ( ) &&
! this . providers . vm . RemixSimulatorProvider . Accounts . accounts [ address ]
) {
return reject ( 'Invalid account selected' )
}
return resolve ( address )
@ -743,21 +1082,44 @@ export class Blockchain extends Plugin {
return
}
const tx = { to : args.to , data : args.data.dataHex , useCall : args.useCall , from : fromAddress , value : value , gasLimit : gasLimit , timestamp : args.data.timestamp }
const payLoad = { funAbi : args.data.funAbi , funArgs : args.data.funArgs , contractBytecode : args.data.contractBytecode , contractName : args.data.contractName , contractABI : args.data.contractABI , linkReferences : args.data.linkReferences }
const tx = {
to : args.to ,
data : args.data.dataHex ,
useCall : args.useCall ,
from : fromAddress ,
value : value ,
gasLimit : gasLimit ,
timestamp : args.data.timestamp
}
const payLoad = {
funAbi : args.data.funAbi ,
funArgs : args.data.funArgs ,
contractBytecode : args.data.contractBytecode ,
contractName : args.data.contractName ,
contractABI : args.data.contractABI ,
linkReferences : args.data.linkReferences
}
if ( ! tx . timestamp ) tx . timestamp = Date . now ( )
const timestamp = tx . timestamp
this . _triggerEvent ( 'initiatingTransaction' , [ timestamp , tx , payLoad ] )
try {
this . txRunner . rawRun ( tx , confirmationCb , continueCb , promptCb ,
this . txRunner . rawRun (
tx ,
confirmationCb ,
continueCb ,
promptCb ,
async ( error , result ) = > {
if ( error ) {
if ( typeof ( error ) !== 'string' ) {
if ( typeof error !== 'string' ) {
if ( error . message ) error = error . message
else {
try { error = 'error: ' + JSON . stringify ( error ) } catch ( e ) { console . log ( e ) }
try {
error = 'error: ' + JSON . stringify ( error )
} catch ( e ) {
console . log ( e )
}
}
}
return reject ( error )
@ -766,23 +1128,39 @@ export class Blockchain extends Plugin {
const isVM = this . executionContext . isVM ( )
if ( isVM && tx . useCall ) {
try {
result . transactionHash = await this . web3 ( ) . eth . getHashFromTagBySimulator ( timestamp )
result . transactionHash =
await this . web3 ( ) . eth . getHashFromTagBySimulator ( timestamp )
} catch ( e ) {
console . log ( 'unable to retrieve back the "call" hash' , e )
}
}
const eventName = ( tx . useCall ? 'callExecuted' : 'transactionExecuted' )
this . _triggerEvent ( eventName , [ error , tx . from , tx . to , tx . data , tx . useCall , result , timestamp , payLoad ] )
const eventName = tx . useCall
? 'callExecuted'
: 'transactionExecuted'
this . _triggerEvent ( eventName , [
error ,
tx . from ,
tx . to ,
tx . data ,
tx . useCall ,
result ,
timestamp ,
payLoad
] )
return resolve ( { result , tx } )
}
)
} catch ( err ) {
let error = err
if ( error && ( typeof ( error ) !== 'string' ) ) {
if ( error && typeof error !== 'string' ) {
if ( error . message ) error = error . message
else {
try { error = 'error: ' + JSON . stringify ( error ) } catch ( e ) { console . log ( e ) }
try {
error = 'error: ' + JSON . stringify ( error )
} catch ( e ) {
console . log ( e )
}
}
}
return reject ( error )
@ -804,18 +1182,26 @@ export class Blockchain extends Plugin {
let execResult
let returnValue = null
if ( isVM ) {
const hhlogs = await this . web3 ( ) . eth . getHHLogsForTx ( txResult . transactionHash )
const hhlogs = await this . web3 ( ) . eth . getHHLogsForTx (
txResult . transactionHash
)
if ( hhlogs && hhlogs . length ) {
const finalLogs = < div > < div > < b > console . log : < / b > < / div >
{
hhlogs . map ( ( log ) = > {
const finalLogs = (
< div >
< div >
< b > console . log : < / b >
< / div >
{ hhlogs . map ( ( log ) = > {
let formattedLog
// Hardhat implements the same formatting options that can be found in Node.js' console.log,
// which in turn uses util.format: https://nodejs.org/dist/latest-v12.x/docs/api/util.html#util_util_format_format_args
// For example: console.log("Name: %s, Age: %d", remix, 6) will log 'Name: remix, Age: 6'
// We check first arg to determine if 'util.format' is needed
if ( typeof log [ 0 ] === 'string' && ( log [ 0 ] . includes ( '%s' ) || log [ 0 ] . includes ( '%d' ) ) ) {
if (
typeof log [ 0 ] === 'string' &&
( log [ 0 ] . includes ( '%s' ) || log [ 0 ] . includes ( '%d' ) )
) {
formattedLog = format ( log [ 0 ] , . . . log . slice ( 1 ) )
} else {
formattedLog = log . join ( ' ' )
@ -823,15 +1209,29 @@ export class Blockchain extends Plugin {
return < div > { formattedLog } < / div >
} ) }
< / div >
)
_paq . push ( [ 'trackEvent' , 'udapp' , 'hardhat' , 'console.log' ] )
this . call ( 'terminal' , 'logHtml' , finalLogs )
}
execResult = await this . web3 ( ) . eth . getExecutionResultFromSimulator ( txResult . transactionHash )
execResult = await this . web3 ( ) . eth . getExecutionResultFromSimulator (
txResult . transactionHash
)
if ( execResult ) {
// if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value.
returnValue = execResult ? toBuffer ( execResult . returnValue ) : toBuffer ( addHexPrefix ( txResult . result ) || '0x0000000000000000000000000000000000000000000000000000000000000000' )
const compiledContracts = await this . call ( 'compilerArtefacts' , 'getAllContractDatas' )
const vmError = txExecution . checkVMError ( execResult , compiledContracts )
returnValue = execResult
? toBuffer ( execResult . returnValue )
: toBuffer (
addHexPrefix ( txResult . result ) ||
'0x0000000000000000000000000000000000000000000000000000000000000000'
)
const compiledContracts = await this . call (
'compilerArtefacts' ,
'getAllContractDatas'
)
const vmError = txExecution . checkVMError (
execResult ,
compiledContracts
)
if ( vmError . error ) {
return cb ( vmError . message )
}