Merge branch 'master' into targets2

pull/1213/head
bunsenstraat 4 years ago committed by GitHub
commit d2220c889e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 33
      apps/remix-ide-e2e/src/tests/transactionExecution.spec.ts
  2. 2
      apps/remix-ide/src/app/udapp/run-tab.js
  3. 2
      apps/remix-ide/src/app/ui/universal-dapp-ui.js
  4. 6
      apps/remix-ide/src/blockchain/blockchain.js
  5. 48
      libs/remix-lib/src/execution/txExecution.ts
  6. 5
      libs/remix-lib/src/execution/txHelper.ts

@ -137,6 +137,21 @@ module.exports = {
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]') .click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(2)') .waitForElementPresent('.instance:nth-of-type(2)')
},
'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal': function (browser: NightwatchBrowser) {
browser.testContracts('customError.sol', sources[4]['customError.sol'], ['C'])
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]')
.waitForElementPresent('.instance:nth-of-type(3)')
.click('.instance:nth-of-type(3) > div > button')
.clickFunction('g - transact (not payable)')
.journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError')
.journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('2,3,error_string_2')
.journalLastChildIncludes('Debug the transaction to get more information.')
.end() .end()
} }
} }
@ -218,5 +233,23 @@ contract C {
event Test(function() external); event Test(function() external);
}` }`
} }
},
// https://github.com/ethereum/remix-project/issues/1152
{
'customError.sol': {
content: `// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
error CustomError(uint a, uint b, string c);
contract C {
function f() public pure {
revert CustomError(2, 3, "error_string");
}
function g() public {
revert CustomError(2, 3, "error_string_2");
}
}`
}
} }
] ]

@ -41,7 +41,7 @@ export class RunTab extends ViewPlugin {
this.blockchain = blockchain this.blockchain = blockchain
this.fileManager = fileManager this.fileManager = fileManager
this.editor = editor this.editor = editor
this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) } this.logCallback = (msg) => { mainView.getTerminal().logHtml(yo`<pre>${msg}</pre>`) }
this.filePanel = filePanel this.filePanel = filePanel
this.compilersArtefacts = compilersArtefacts this.compilersArtefacts = compilersArtefacts
this.networkModule = networkModule this.networkModule = networkModule

@ -253,7 +253,7 @@ UniversalDAppUI.prototype.runTransaction = function (lookupOnly, args, valArr, i
const params = args.funABI.type !== 'fallback' ? inputsValues : '' const params = args.funABI.type !== 'fallback' ? inputsValues : ''
this.blockchain.runOrCallContractMethod( this.blockchain.runOrCallContractMethod(
args.contractName, args.contractName,
args.contractAbi, args.contractABI,
args.funABI, args.funABI,
inputsValues, inputsValues,
args.address, args.address,

@ -262,6 +262,10 @@ class Blockchain {
} }
if (funABI.type === 'fallback') data.dataHex = value if (funABI.type === 'fallback') data.dataHex = value
if (data) {
data.contractName = contractName
data.contractABI = contractAbi
}
const useCall = funABI.stateMutability === 'view' || funABI.stateMutability === 'pure' const useCall = funABI.stateMutability === 'view' || funABI.stateMutability === 'pure'
this.runTx({ to: address, data, useCall }, confirmationCb, continueCb, promptCb, (error, txResult, _address, returnValue) => { this.runTx({ to: address, data, useCall }, confirmationCb, continueCb, promptCb, (error, txResult, _address, returnValue) => {
if (error) { if (error) {
@ -477,7 +481,7 @@ class Blockchain {
if (execResult) { 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. // 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 && isVM) ? execResult.returnValue : txResult returnValue = (execResult && isVM) ? execResult.returnValue : txResult
const vmError = txExecution.checkVMError(execResult) const vmError = txExecution.checkVMError(execResult, args.data.contractABI)
if (vmError.error) { if (vmError.error) {
return cb(vmError.message) return cb(vmError.message)
} }

@ -1,5 +1,6 @@
'use strict' 'use strict'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { getFunctionFragment } from './txHelper'
/** /**
* deploy the given contract * deploy the given contract
@ -56,7 +57,7 @@ export function callFunction (from, to, data, value, gasLimit, funAbi, txRunner,
* @param {Object} execResult - execution result given by the VM * @param {Object} execResult - execution result given by the VM
* @return {Object} - { error: true/false, message: DOMNode } * @return {Object} - { error: true/false, message: DOMNode }
*/ */
export function checkVMError (execResult) { export function checkVMError (execResult, abi) {
const errorCode = { const errorCode = {
OUT_OF_GAS: 'out of gas', OUT_OF_GAS: 'out of gas',
STACK_UNDERFLOW: 'stack underflow', STACK_UNDERFLOW: 'stack underflow',
@ -88,19 +89,48 @@ export function checkVMError (execResult) {
ret.error = true ret.error = true
} else if (exceptionError === errorCode.REVERT) { } else if (exceptionError === errorCode.REVERT) {
const returnData = execResult.returnValue const returnData = execResult.returnValue
// It is the hash of Error(string) const returnDataHex = returnData.slice(0, 4).toString('hex')
if (returnData && (returnData.slice(0, 4).toString('hex') === '08c379a0')) { let customError
const abiCoder = new ethers.utils.AbiCoder() if (abi) {
const reason = abiCoder.decode(['string'], returnData.slice(4))[0] let decodedCustomErrorInputs
msg = `\tThe transaction has been reverted to the initial state.\nReason provided by the contract: "${reason}".` for (const item of abi) {
} else { if (item.type === 'error') {
msg = '\tThe transaction has been reverted to the initial state.\nNote: The called function should be payable if you send value and the value you send should be less than your current balance.' // 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
decodedCustomErrorInputs = fn.decodeFunctionData(fn.getFunction(item.name), returnData)
break
}
}
}
if (decodedCustomErrorInputs) {
msg = '\tThe transaction has been reverted to the initial state.\nError provided by the contract:'
msg += `\n${customError}`
msg += '\nParameters:'
msg += `\n${decodedCustomErrorInputs}`
}
}
if (!customError) {
// It is the hash of Error(string)
if (returnData && (returnDataHex === '08c379a0')) {
const abiCoder = new ethers.utils.AbiCoder()
const reason = abiCoder.decode(['string'], returnData.slice(4))[0]
msg = `\tThe transaction has been reverted to the initial state.\nReason provided by the contract: "${reason}".`
} else {
msg = '\tThe transaction has been reverted to the initial state.\nNote: The called function should be payable if you send value and the value you send should be less than your current balance.'
}
} }
ret.error = true ret.error = true
} else if (exceptionError === errorCode.STATIC_STATE_CHANGE) { } else if (exceptionError === errorCode.STATIC_STATE_CHANGE) {
msg = '\tState changes is not allowed in Static Call context\n' msg = '\tState changes is not allowed in Static Call context\n'
ret.error = true ret.error = true
} }
ret.message = `${error}${exceptionError}${msg}\tDebug the transaction to get more information.` ret.message = `${error}\n${exceptionError}\n${msg}\nDebug the transaction to get more information.`
return ret return ret
} }

@ -38,6 +38,11 @@ export function encodeFunctionId (funABI) {
return abi.getSighash(funABI.name) return abi.getSighash(funABI.name)
} }
export function getFunctionFragment (funABI): ethers.utils.Interface {
if (funABI.type === 'fallback' || funABI.type === 'receive') return null
return new ethers.utils.Interface([funABI])
}
export function sortAbiFunction (contractabi) { export function sortAbiFunction (contractabi) {
// Check if function is constant (introduced with Solidity 0.6.0) // Check if function is constant (introduced with Solidity 0.6.0)
const isConstant = ({ stateMutability }) => stateMutability === 'view' || stateMutability === 'pure' const isConstant = ({ stateMutability }) => stateMutability === 'view' || stateMutability === 'pure'

Loading…
Cancel
Save