Merge branch 'master' into personalm

pull/1220/head
Liana Husikyan 4 years ago committed by GitHub
commit e43c881ef1
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. 36
      libs/remix-lib/src/execution/txExecution.ts
  6. 5
      libs/remix-lib/src/execution/txHelper.ts
  7. 8
      libs/remix-url-resolver/tests/test.ts

@ -137,6 +137,21 @@ module.exports = {
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite
.click('#runTabView button[class^="instanceButton"]')
.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()
}
}
@ -218,5 +233,23 @@ contract C {
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.fileManager = fileManager
this.editor = editor
this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) }
this.logCallback = (msg) => { mainView.getTerminal().logHtml(yo`<pre>${msg}</pre>`) }
this.filePanel = filePanel
this.compilersArtefacts = compilersArtefacts
this.networkModule = networkModule

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

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

@ -1,5 +1,6 @@
'use strict'
import { ethers } from 'ethers'
import { getFunctionFragment } from './txHelper'
/**
* 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
* @return {Object} - { error: true/false, message: DOMNode }
*/
export function checkVMError (execResult) {
export function checkVMError (execResult, abi) {
const errorCode = {
OUT_OF_GAS: 'out of gas',
STACK_UNDERFLOW: 'stack underflow',
@ -88,19 +89,48 @@ export function checkVMError (execResult) {
ret.error = true
} else if (exceptionError === errorCode.REVERT) {
const returnData = execResult.returnValue
const returnDataHex = returnData.slice(0, 4).toString('hex')
let customError
if (abi) {
let decodedCustomErrorInputs
for (const item of 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
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 && (returnData.slice(0, 4).toString('hex') === '08c379a0')) {
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
} else if (exceptionError === errorCode.STATIC_STATE_CHANGE) {
msg = '\tState changes is not allowed in Static Call context\n'
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
}

@ -38,6 +38,11 @@ export function encodeFunctionId (funABI) {
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) {
// Check if function is constant (introduced with Solidity 0.6.0)
const isConstant = ({ stateMutability }) => stateMutability === 'view' || stateMutability === 'pure'

@ -59,7 +59,7 @@ describe('testRunner', () => {
// Test github import
describe('test getting github imports', () => {
const urlResolver = new RemixURLResolver()
const fileName: string = 'github.com/MathCody/solidity-examples/greeter/greeter.sol'
const fileName: string = 'github.com/ethential/solidity-examples/solidity-features-check/greeter.sol'
let results: object = {}
before(done => {
@ -78,8 +78,8 @@ describe('testRunner', () => {
})
it('should return contract content of given github path', () => {
const expt: object = {
cleanUrl: 'MathCody/solidity-examples/greeter/greeter.sol',
content: 'pragma solidity >=0.5.0 <0.6.0;\nimport \"../mortal/mortal.sol\";\n\ncontract Greeter is Mortal {\n /* Define variable greeting of the type string */\n string greeting;\n\n /* This runs when the contract is executed */\n constructor(string memory _greeting) public {\n greeting = _greeting;\n }\n\n /* Main function */\n function greet() public view returns (string memory) {\n return greeting;\n }\n}',
cleanUrl: 'ethential/solidity-examples/solidity-features-check/greeter.sol',
content: 'pragma solidity >=0.7.0;\nimport \"./mortal.sol\";\n// SPDX-License-Identifier: GPL-3.0\n\ncontract Greeter is Mortal {\n /* Define variable greeting of the type string */\n string greeting;\n\n /* This runs when the contract is executed */\n constructor(string memory _greeting) {\n greeting = _greeting;\n }\n\n /* Main function */\n function greet() public view returns (string memory) {\n return greeting;\n }\n}\n\n// 0x37aA58B2cE3Bb9576EEBCD51315070eA8806b7c4\n',
type: 'github'
}
assert.deepEqual(results, expt)
@ -268,6 +268,7 @@ describe('testRunner', () => {
})
// Test SWARM imports
/*
describe('test getting SWARM imports', () => {
const urlResolver = new RemixURLResolver()
const fileName = 'bzz-raw://a728627437140f2b0b46c1bcfb0de2126d18b40e9b61c3e31bd96abebf714619'
@ -297,6 +298,7 @@ describe('testRunner', () => {
assert.deepEqual(results, expt)
})
})
*/
})
})
})

Loading…
Cancel
Save