add natspec info to error report

pull/1297/head
yann300 3 years ago
parent 103274a24d
commit 9a91aad983
  1. 13
      apps/remix-ide-e2e/src/tests/transactionExecution.spec.ts
  2. 8
      apps/remix-ide/src/app/ui/universal-dapp-ui.js
  3. 5
      apps/remix-ide/src/blockchain/blockchain.js
  4. 14
      libs/remix-lib/src/execution/txExecution.ts

@ -148,9 +148,14 @@ module.exports = {
.click('.instance:nth-of-type(3) > div > button')
.clickFunction('g - transact (not payable)')
.journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError')
.journalLastChildIncludes('CustomError: error description')
.journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('2,3,error_string_2')
.journalLastChildIncludes('"value": "2",')
.journalLastChildIncludes('"value": "3",')
.journalLastChildIncludes('"value": "error_string_2",')
.journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')
.journalLastChildIncludes('Debug the transaction to get more information.')
},
@ -256,6 +261,10 @@ contract C {
pragma solidity ^0.8.4;
/// error description
/// @param a param1
/// @param b param2
/// @param c param3
error CustomError(uint a, uint b, string c);
contract C {
function f() public pure {

@ -44,14 +44,14 @@ UniversalDAppUI.prototype.renderInstance = function (contract, address, contract
noInstances.parentNode.removeChild(noInstances)
}
const abi = txHelper.sortAbiFunction(contract.abi)
return this.renderInstanceFromABI(abi, address, contractName)
return this.renderInstanceFromABI(abi, address, contractName, contract)
}
// TODO this function was named before "appendChild".
// this will render an instance: contract name, contract address, and all the public functions
// basically this has to be called for the "atAddress" (line 393) and when a contract creation succeed
// this returns a DOM element
UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address, contractName) {
UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address, contractName, contract) {
const self = this
address = (address.slice(0, 2) === '0x' ? '' : '0x') + address.toString('hex')
address = ethJSUtil.toChecksumAddress(address)
@ -117,7 +117,8 @@ UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address
funABI: funABI,
address: address,
contractABI: contractABI,
contractName: contractName
contractName: contractName,
contract
}))
})
@ -255,6 +256,7 @@ UniversalDAppUI.prototype.runTransaction = function (lookupOnly, args, valArr, i
args.contractName,
args.contractABI,
args.funABI,
args.contract,
inputsValues,
args.address,
params,

@ -249,7 +249,7 @@ class Blockchain {
return txlistener
}
runOrCallContractMethod (contractName, contractAbi, funABI, 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) => {
if (error) {
@ -265,6 +265,7 @@ class Blockchain {
if (data) {
data.contractName = contractName
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) => {
@ -490,7 +491,7 @@ class Blockchain {
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 ? execResult.returnValue : toBuffer(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000')
const vmError = txExecution.checkVMError(execResult, args.data.contractABI)
const vmError = txExecution.checkVMError(execResult, args.data.contractABI, args.data.contract)
if (vmError.error) {
return cb(vmError.message)
}

@ -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 checkVMError (execResult, abi) {
export function checkVMError (execResult, abi, contract) {
const errorCode = {
OUT_OF_GAS: 'out of gas',
STACK_UNDERFLOW: 'stack underflow',
@ -107,9 +107,19 @@ export function checkVMError (execResult, abi) {
let functionDesc = fn.getFunction(item.name)
let decodedCustomErrorInputs = fn.decodeFunctionData(functionDesc, returnData)
decodedCustomErrorInputsClean = {}
let devdoc = {}
if (contract && fn.functions && Object.keys(fn.functions).length) {
const functionSignature = Object.keys(fn.functions)[0]
devdoc = contract.object.devdoc.errors[functionSignature][0] || {}
let userdoc = contract.object.userdoc.errors[functionSignature][0] || {}
if (userdoc) customError += ' : ' + (userdoc as any).notice
}
for (const input of functionDesc.inputs) {
const v = decodedCustomErrorInputs[input.name]
decodedCustomErrorInputsClean[input.name] = v.toString ? v.toString() : v
decodedCustomErrorInputsClean[input.name] = {
value: v.toString ? v.toString() : v,
documentation: (devdoc as any).params[input.name]
}
}
break
}

Loading…
Cancel
Save