diff --git a/contracts/solidity/errors/Errors.sol b/contracts/solidity/errors/Errors.sol index db50b90ba..172694312 100644 --- a/contracts/solidity/errors/Errors.sol +++ b/contracts/solidity/errors/Errors.sol @@ -1,25 +1,60 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; +import { ErrorsExternal } from "./ErrorsExternal.sol"; + contract Errors { - constructor() { + error InsufficientBalance(uint256 available, uint256 required); + ErrorsExternal errorsExternal; + event Result(uint code, string message); + + constructor(address errorsExternalAddr) { + errorsExternal = ErrorsExternal(errorsExternalAddr); } - function assertCheck(bool condition) public pure returns (bool) { + function assertCheck(bool condition) external pure returns (bool) { assert(condition); return true; } - function requireCheck(bool shouldRevert) public pure returns (bool) { + function requireCheck(bool shouldRevert) external pure returns (bool) { require(shouldRevert); return true; } - function revertCheck() public pure returns (bool) { + function revertCheck() external pure returns (bool) { revert(); } - function revertWithMessageCheck(string calldata message) public pure returns (bool) { + function revertWithMessageCheck(string calldata message) external pure returns (bool) { revert(message); } + + function revertWithCustomError() external pure returns (bool) { + revert InsufficientBalance(1, 100); + } + + function tryCatchWithSimpleRevert() external returns (int value, bool success) { + try errorsExternal.revertSimple() returns (bool v) { + return (1, v); + } catch (bytes memory) { + emit Result(0, 'revertSimple'); + } + } + + function tryCatchWithErrorMessageRevert(string memory message) external returns (int value, bool success) { + try errorsExternal.revertWithErrorMessage(message) returns (bool v) { + return (1, v); + } catch Error(string memory message) { + emit Result(0, message); + } + } + + function tryCatchWithPanic() external returns (uint value, bool success) { + try errorsExternal.panic() returns (uint v) { + return (v, false); + } catch Panic(uint errorCode) { + emit Result(errorCode, 'panic'); + } + } } diff --git a/contracts/solidity/errors/ErrorsExternal.sol b/contracts/solidity/errors/ErrorsExternal.sol new file mode 100644 index 000000000..2a2d305f3 --- /dev/null +++ b/contracts/solidity/errors/ErrorsExternal.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +contract ErrorsExternal { + error InsufficientBalance(uint256 available, uint256 required); + + function revertWithCustomError() external pure returns (bool) { + revert InsufficientBalance(1, 100); + } + + function revertSimple() external pure returns (bool) { + revert(); + } + + function revertWithErrorMessage(string memory message) external pure returns (bool) { + revert(message); + } + + function panic() external pure returns (uint) { + return uint(4)/uint(0); + } +} diff --git a/test/constants.js b/test/constants.js index 012fa62d5..6294ecf65 100644 --- a/test/constants.js +++ b/test/constants.js @@ -101,7 +101,6 @@ const Contract = { ExchangeRateMock: 'ExchangeRateMock', PrngSystemContract: 'PrngSystemContract', Concatenation: 'Concatenation', - Errors: 'Errors', Transaction: 'Transaction', MessageFrameAddresses: 'MessageFrameAddresses', New: 'New', diff --git a/test/solidity/errors/errors.js b/test/solidity/errors/errors.js index 7f9919a9f..6a11104ce 100644 --- a/test/solidity/errors/errors.js +++ b/test/solidity/errors/errors.js @@ -23,54 +23,104 @@ const { ethers } = require('hardhat') const Constants = require('../../constants') describe('@solidityequiv2 Solidity Errors', function () { - let signers - let contract + let contract, hasError before(async function () { - signers = await ethers.getSigners() + const factoryErrorsExternal = await ethers.getContractFactory('ErrorsExternal') + contractExternal = await factoryErrorsExternal.deploy() - const factory = await ethers.getContractFactory(Constants.Contract.Errors) - contract = await factory.deploy() + const factory = await ethers.getContractFactory('Errors') + contract = await factory.deploy(contractExternal.address) }) - it('confirm assert works', async function () { + beforeEach(async function () { + hasError = false + }) + + it('should confirm assert works', async function () { try { const res = await contract.assertCheck(1 == 1) expect(res).to.equal(true) await contract.assertCheck(1 > 1) } catch (err) { + hasError = true expect(err).to.exist } + expect(hasError).to.equal(true) }) - it('confirm require works', async function () { + it('should confirm require works', async function () { try { const resReverted = await contract.requireCheck(true) expect(resReverted).to.equal(true) - const res = await contract.requireCheck(false) + await contract.requireCheck(false) } catch (err) { + hasError = true expect(err).to.exist } + expect(hasError).to.equal(true) }) - it('confirm revert works', async function () { + it('should confirm revert works', async function () { try { await contract.revertCheck() } catch (err) { + hasError = true expect(err).to.exist } + expect(hasError).to.equal(true) }) - it('confirm revert with message works', async function () { + it('should confirm revert with message works', async function () { const message = "We unfortunalty need to revert this transaction" try { await contract.revertWithMessageCheck(message) } catch (err) { + hasError = true expect(err.reason).to.exist expect(err.reason).to.equal(message) } + expect(hasError).to.equal(true) + }) + + it('should confirm revert with custom error works', async function () { + try { + await contract.revertWithCustomError() + } catch (err) { + hasError = true + expect(err.code).to.equal('CALL_EXCEPTION') + expect(err.errorName).to.equal('InsufficientBalance') + expect(err.errorArgs.available).to.equal(ethers.BigNumber.from(1)) + expect(err.errorArgs.required).to.equal(ethers.BigNumber.from(100)) + } + expect(hasError).to.equal(true) + }) + + it('should confirm try/catch with simple revert', async function () { + const tx = await contract.tryCatchWithSimpleRevert() + const receipt = await tx.wait() + expect(receipt).to.exist + expect(receipt.events[0].args.code).to.equal(0) + expect(receipt.events[0].args.message).to.equal('revertSimple') + }) + + it('should confirm try/catch revert with error message', async function () { + const message = "We unfortunalty need to revert this transaction" + const tx = await contract.tryCatchWithErrorMessageRevert(message) + const receipt = await tx.wait() + expect(receipt).to.exist + expect(receipt.events[0].args.code).to.equal(0) + expect(receipt.events[0].args.message).to.equal(message) + }) + + it('should confirm try/catch revert with panic', async function () { + const tx = await contract.tryCatchWithPanic() + const receipt = await tx.wait() + expect(receipt).to.exist + expect(receipt.events[0].args.code).to.equal(18) + expect(receipt.events[0].args.message).to.equal('panic') }) })