@ -57,7 +57,7 @@ export function callFunction (from, to, data, value, gasLimit, funAbi, txRunner,
* @param { Object } execResult - execution result given by the VM
* @return { Object } - { error : true / false , message : DOMNode }
* /
export function checkVM Error ( execResult , compiledContracts ) {
export function checkError ( execResult , compiledContracts , isInjectedWeb3 ) {
const errorCode = {
OUT_OF_GAS : 'out of gas' ,
STACK_UNDERFLOW : 'stack underflow' ,
@ -75,11 +75,11 @@ export function checkVMError (execResult, compiledContracts) {
error : false ,
message : ''
}
if ( ! execResult . exceptionError ) {
if ( ! execResult . exceptionError && ! isInjectedWeb3 ) {
return ret
}
const exceptionError = execResult . exceptionError . error || ''
const error = ` VM error : ${ exceptionError } . \ n `
const exceptionError = ( execResult . exceptionError && execResult . exceptionError . error ) || ''
const error = ` Error occured : ${ isInjectedWeb3 ? execResult.error : exceptionError } . \ n `
let msg
if ( exceptionError === errorCode . INVALID_OPCODE ) {
msg = '\t\n\tThe execution might have thrown.\n'
@ -87,8 +87,8 @@ export function checkVMError (execResult, compiledContracts) {
} else if ( exceptionError === errorCode . OUT_OF_GAS ) {
msg = '\tThe transaction ran out of gas. Please increase the Gas Limit.\n'
ret . error = true
} else if ( exceptionError === errorCode . REVERT ) {
const returnData = execResult . returnValue
} else if ( exceptionError === errorCode . REVERT || ( isInjectedWeb3 && execResult . error === 'execution reverted' ) ) {
const returnData = isInjectedWeb3 ? execResult.errorData : execResult. returnValue
const returnDataHex = returnData . slice ( 2 , 10 )
let customError
if ( compiledContracts ) {
@ -172,78 +172,4 @@ export function checkVMError (execResult, compiledContracts) {
}
ret . message = ` ${ error } \ n ${ exceptionError } \ n ${ msg } \ nDebug the transaction to get more information. `
return ret
}
export function checkInjectedError ( errorObj , compiledContracts ) {
if ( errorObj . error === 'execution reverted' ) {
const returnData = errorObj . errorData
const returnDataHex = returnData . slice ( 2 , 10 )
let customError
let msg = errorObj . error
if ( compiledContracts ) {
let decodedCustomErrorInputsClean
for ( const file of Object . keys ( compiledContracts ) ) {
for ( const contractName of Object . keys ( compiledContracts [ file ] ) ) {
const contract = compiledContracts [ file ] [ contractName ]
for ( const item of contract . abi ) {
if ( item . type === 'error' ) {
// ethers doesn't crash anymore if "error" type is specified, but it doesn't extract the errors. see:
// https://github.com/ethers-io/ethers.js/commit/bd05aed070ac9e1421a3e2bff2ceea150bedf9b7
// we need here to fake the type, so the "getSighash" function works properly
const fn = getFunctionFragment ( { . . . item , type : 'function' , stateMutability : 'nonpayable' } )
if ( ! fn ) continue
const sign = fn . getSighash ( item . name )
if ( ! sign ) continue
if ( returnDataHex === sign . replace ( '0x' , '' ) ) {
customError = item . name
const functionDesc = fn . getFunction ( item . name )
// decoding error parameters
const decodedCustomErrorInputs = fn . decodeFunctionData ( functionDesc , returnData )
decodedCustomErrorInputsClean = { }
let devdoc = { }
// "contract" reprensents the compilation result containing the NATSPEC documentation
if ( contract && fn . functions && Object . keys ( fn . functions ) . length ) {
const functionSignature = Object . keys ( fn . functions ) [ 0 ]
// we check in the 'devdoc' if there's a developer documentation for this error
try {
devdoc = ( contract . devdoc . errors && contract . devdoc . errors [ functionSignature ] [ 0 ] ) || { }
} catch ( e ) {
console . error ( e . message )
}
// we check in the 'userdoc' if there's an user documentation for this error
try {
const userdoc = ( contract . userdoc . errors && contract . userdoc . errors [ functionSignature ] [ 0 ] ) || { }
if ( userdoc && ( userdoc as any ) . notice ) customError += ' : ' + ( userdoc as any ) . notice // we append the user doc if any
} catch ( e ) {
console . error ( e . message )
}
}
let inputIndex = 0
for ( const input of functionDesc . inputs ) {
const inputKey = input . name || inputIndex
const v = decodedCustomErrorInputs [ inputKey ]
decodedCustomErrorInputsClean [ inputKey ] = {
value : v.toString ? v . toString ( ) : v
}
if ( devdoc && ( devdoc as any ) . params ) {
decodedCustomErrorInputsClean [ input . name ] . documentation = ( devdoc as any ) . params [ inputKey ] // we add the developer documentation for this input parameter if any
}
inputIndex ++
}
break
}
}
}
}
}
if ( decodedCustomErrorInputsClean ) {
msg += '\tThe transaction has been reverted to the initial state.\nError provided by the contract:'
msg += ` \ n ${ customError } `
msg += '\nParameters:'
msg += ` \ n ${ JSON . stringify ( decodedCustomErrorInputsClean , null , ' ' ) } `
}
}
return msg
}
}