Skip to content

Commit 4622881

Browse files
authoredMay 6, 2022
😨 Waffle-provider support panic codes (#721)
1 parent ba71ce4 commit 4622881

File tree

8 files changed

+147
-52
lines changed

8 files changed

+147
-52
lines changed
 

‎.changeset/dirty-badgers-sin.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@ethereum-waffle/chai": patch
3+
"@ethereum-waffle/provider": patch
4+
---
5+
6+
Support panic codes in ganache

‎pnpm-lock.yaml

+3-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎waffle-chai/src/matchers/revertedWith.ts

-7
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,6 @@ export function supportRevertedWith(Assertion: Chai.AssertionStatic) {
8080
const decodeHardhatError = (error: any) => {
8181
const tryDecode = (error: any) => {
8282
const errorString = String(error);
83-
{
84-
const regexp = new RegExp('VM Exception while processing transaction: reverted with reason string \'(.*)\'');
85-
const matches = regexp.exec(errorString);
86-
if (matches && matches.length >= 1) {
87-
return matches[1];
88-
}
89-
}
9083
{
9184
const regexp = new RegExp('VM Exception while processing transaction: reverted with custom error \'(.*)\'');
9285
const matches = regexp.exec(errorString);

‎waffle-chai/test/contracts/Matchers.ts

+84-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const MATCHERS_SOURCE = `
2-
pragma solidity ^0.6.0;
2+
pragma solidity ^0.8.0;
33
44
contract Matchers {
55
uint counter;
@@ -20,6 +20,11 @@ export const MATCHERS_SOURCE = `
2020
revert("Revert cause");
2121
}
2222
23+
function doPanic() public pure {
24+
uint d = 0;
25+
uint x = 1 / d;
26+
}
27+
2328
function doRevertWithComplexReason() public pure {
2429
revert("Revert cause (with complex reason)");
2530
}
@@ -50,17 +55,84 @@ export const MATCHERS_SOURCE = `
5055
`;
5156

5257
export const MATCHERS_ABI = [
53-
'function doNothing() public pure',
54-
'function doModify() public',
55-
'function doThrow() public pure',
56-
'function doRevert() public pure',
57-
'function doRevertWithComplexReason() public pure',
58-
'function doRequireFail() public pure',
59-
'function doRequireSuccess() public pure',
60-
'function doThrowAndModify() public',
61-
'function doRevertAndModify() public',
62-
'function doRequireFailAndModify() public'
58+
{
59+
inputs: [],
60+
name: 'doModify',
61+
outputs: [],
62+
stateMutability: 'nonpayable',
63+
type: 'function'
64+
},
65+
{
66+
inputs: [],
67+
name: 'doNothing',
68+
outputs: [],
69+
stateMutability: 'pure',
70+
type: 'function'
71+
},
72+
{
73+
inputs: [],
74+
name: 'doPanic',
75+
outputs: [],
76+
stateMutability: 'pure',
77+
type: 'function'
78+
},
79+
{
80+
inputs: [],
81+
name: 'doRequireFail',
82+
outputs: [],
83+
stateMutability: 'pure',
84+
type: 'function'
85+
},
86+
{
87+
inputs: [],
88+
name: 'doRequireFailAndModify',
89+
outputs: [],
90+
stateMutability: 'nonpayable',
91+
type: 'function'
92+
},
93+
{
94+
inputs: [],
95+
name: 'doRequireSuccess',
96+
outputs: [],
97+
stateMutability: 'pure',
98+
type: 'function'
99+
},
100+
{
101+
inputs: [],
102+
name: 'doRevert',
103+
outputs: [],
104+
stateMutability: 'pure',
105+
type: 'function'
106+
},
107+
{
108+
inputs: [],
109+
name: 'doRevertAndModify',
110+
outputs: [],
111+
stateMutability: 'nonpayable',
112+
type: 'function'
113+
},
114+
{
115+
inputs: [],
116+
name: 'doRevertWithComplexReason',
117+
outputs: [],
118+
stateMutability: 'pure',
119+
type: 'function'
120+
},
121+
{
122+
inputs: [],
123+
name: 'doThrow',
124+
outputs: [],
125+
stateMutability: 'pure',
126+
type: 'function'
127+
},
128+
{
129+
inputs: [],
130+
name: 'doThrowAndModify',
131+
outputs: [],
132+
stateMutability: 'nonpayable',
133+
type: 'function'
134+
}
63135
];
64136

65137
// eslint-disable-next-line max-len
66-
export const MATCHERS_BYTECODE = '608060405234801561001057600080fd5b50610446806100206000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c8063afc874d211610066578063afc874d2146100d5578063b217ca11146100df578063be3e2e60146100e9578063eacf8a57146100f3578063fff78f9c146100fd5761009e565b806301236db4146100a35780632f576f20146100ad578063841caf38146100b7578063a6f34dcb146100c1578063af9b5739146100cb575b600080fd5b6100ab610107565b005b6100b5610185565b005b6100bf610187565b005b6100c96101a1565b005b6100d3610227565b005b6100dd610278565b005b6100e76102e6565b005b6100f16102f8565b005b6100fb61036e565b005b6101056103e4565b005b600160008082825401925050819055506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f526576657274206361757365000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b60016000808282540192505081905550600061019f57fe5b565b600160008082825401925050819055506000610225576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f526571756972652063617573650000000000000000000000000000000000000081525060200191505060405180910390fd5b565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806103ef6022913960400191505060405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f526576657274206361757365000000000000000000000000000000000000000081525060200191505060405180910390fd5b60016000808282540192505081905550565b600161036c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f4e6576657220746f206265207365656e0000000000000000000000000000000081525060200191505060405180910390fd5b565b60006103e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f526571756972652063617573650000000000000000000000000000000000000081525060200191505060405180910390fd5b565b60006103ec57fe5b56fe52657665727420636175736520287769746820636f6d706c657820726561736f6e29a26469706673582212202c86634aa4c6cf8a67f1325a400b5ccc8e1376865e933bf14efaa0f187772cac64736f6c63430006000033';
138+
export const MATCHERS_BYTECODE = '608060405234801561001057600080fd5b50610671806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063af9b573911610071578063af9b5739146100e0578063afc874d2146100ea578063b217ca11146100f4578063be3e2e60146100fe578063eacf8a5714610108578063fff78f9c14610112576100a9565b806301236db4146100ae5780632f576f20146100b8578063841caf38146100c25780639817185d146100cc578063a6f34dcb146100d6575b600080fd5b6100b661011c565b005b6100c0610170565b005b6100ca610172565b005b6100d461019c565b005b6100de6101b2565b005b6100e861020e565b005b6100f2610249565b005b6100fc610284565b005b61010661029f565b005b6101106102e2565b005b61011a610325565b005b600160008082825461012e9190610453565b925050819055506040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610167906103c2565b60405180910390fd5b565b60016000808282546101849190610453565b92505081905550600061019a576101996104e4565b5b565b6000808160016101ac91906104a9565b90505050565b60016000808282546101c49190610453565b92505081905550600061020c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610203906103e2565b60405180910390fd5b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024090610402565b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161027b906103c2565b60405180910390fd5b60016000808282546102969190610453565b92505081905550565b60016102e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d790610422565b60405180910390fd5b565b6000610323576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031a906103e2565b60405180910390fd5b565b6000610334576103336104e4565b5b565b6000610343600c83610442565b915061034e82610571565b602082019050919050565b6000610366600d83610442565b91506103718261059a565b602082019050919050565b6000610389602283610442565b9150610394826105c3565b604082019050919050565b60006103ac601083610442565b91506103b782610612565b602082019050919050565b600060208201905081810360008301526103db81610336565b9050919050565b600060208201905081810360008301526103fb81610359565b9050919050565b6000602082019050818103600083015261041b8161037c565b9050919050565b6000602082019050818103600083015261043b8161039f565b9050919050565b600082825260208201905092915050565b600061045e826104da565b9150610469836104da565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561049e5761049d610513565b5b828201905092915050565b60006104b4826104da565b91506104bf836104da565b9250826104cf576104ce610542565b5b828204905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f5265766572742063617573650000000000000000000000000000000000000000600082015250565b7f5265717569726520636175736500000000000000000000000000000000000000600082015250565b7f52657665727420636175736520287769746820636f6d706c657820726561736f60008201527f6e29000000000000000000000000000000000000000000000000000000000000602082015250565b7f4e6576657220746f206265207365656e0000000000000000000000000000000060008201525056fea26469706673582212200d6f653037fb208b2c580e808f575116267849837dff0eb0b0e67eb37bed45f464736f6c63430008070033';

‎waffle-chai/test/matchers/revertedWithTest.ts

+4
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,8 @@ export const revertedWithTest = (provider: MockProvider) => {
181181
expect(Promise.reject('Always reject')).to.be.revertedWith('Always reject')
182182
).to.be.eventually.rejected;
183183
});
184+
185+
it('Handle panic error', async () => {
186+
await expect(matchers.doPanic()).to.be.revertedWith('panic code 0x12');
187+
});
184188
};

‎waffle-hardhat/contracts/Panic.sol

-9
This file was deleted.

‎waffle-hardhat/test/reverted.test.ts

+8-18
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {expect} from 'chai';
33
import {MockProvider} from 'ethereum-waffle';
44
import {revertedTest, revertedWithTest} from '@ethereum-waffle/chai/test';
55
import {ContractFactory} from 'ethers';
6-
import Panic from '../build/contracts/Panic.sol/Panic.json';
76
import CustomError from '../build/contracts/CustomError.sol/Matchers.json';
87

98
describe('INTEGRATION: Matchers: reverted', () => {
@@ -24,22 +23,13 @@ describe('INTEGRATION: Matchers: revertedWith', () => {
2423
});
2524

2625
revertedWithTest(provider);
27-
});
28-
29-
it('Panic code', async () => {
30-
await waffle.provider.send('hardhat_reset', []);
31-
const wallets = waffle.provider.getWallets();
32-
const wallet = wallets[0];
33-
const factory = new ContractFactory(Panic.abi, Panic.bytecode, wallet);
34-
const panicContract = await factory.deploy();
35-
await expect(panicContract.panic()).to.be.revertedWith('panic code 0x32');
36-
});
3726

38-
it('Handle custom error', async () => {
39-
await waffle.provider.send('hardhat_reset', []);
40-
const wallets = waffle.provider.getWallets();
41-
const wallet = wallets[0];
42-
const factory = new ContractFactory(CustomError.abi, CustomError.bytecode, wallet);
43-
const matchers = await factory.deploy();
44-
await expect(matchers.doRevertWithCustomError()).to.be.revertedWith('CustomError(0)');
27+
it('Handle custom error', async () => {
28+
await waffle.provider.send('hardhat_reset', []);
29+
const wallets = waffle.provider.getWallets();
30+
const wallet = wallets[0];
31+
const factory = new ContractFactory(CustomError.abi, CustomError.bytecode, wallet);
32+
const matchers = await factory.deploy();
33+
await expect(matchers.doRevertWithCustomError()).to.be.revertedWith('CustomError(0)');
34+
});
4535
});

‎waffle-provider/src/revertString.ts

+42-4
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,61 @@ import {toUtf8String} from 'ethers/lib/utils';
33
import {Provider} from 'ganache';
44
import {log} from './log';
55

6+
const getHardhatErrorString = (callRevertError: any) => {
7+
const tryDecode = (error: any) => {
8+
const stackTrace = error?.stackTrace;
9+
const errorBuffer = stackTrace?.[stackTrace.length - 1].message?.value;
10+
if (errorBuffer) {
11+
return '0x' + errorBuffer.toString('hex');
12+
}
13+
};
14+
15+
return tryDecode(callRevertError) ?? tryDecode(callRevertError.error);
16+
};
17+
18+
const getGanacheErrorString = (callRevertError: any) => {
19+
return callRevertError?.error?.data;
20+
};
21+
622
/* eslint-disable no-control-regex */
723

824
/**
925
* Decodes a revert string from a failed call/query that reverts on chain.
1026
* @param callRevertError The error catched from performing a reverting call (query)
1127
*/
1228
export const decodeRevertString = (callRevertError: any): string => {
29+
const errorString: string | undefined =
30+
getHardhatErrorString(callRevertError) ??
31+
getGanacheErrorString(callRevertError);
32+
33+
if (errorString === undefined) {
34+
return '';
35+
}
36+
1337
/**
1438
* https://ethereum.stackexchange.com/a/66173
1539
* Numeric.toHexString(Hash.sha3("Error(string)".getBytes())).substring(0, 10)
1640
*/
1741
const errorMethodId = '0x08c379a0';
18-
const errorString: string | undefined = callRevertError?.error?.data;
42+
if (errorString.startsWith(errorMethodId)) {
43+
return toUtf8String('0x' + errorString.substring(138))
44+
.replace(/\x00/g, ''); // Trim null characters.
45+
}
46+
47+
const panicCodeId = '0x4e487b71';
48+
if (errorString.startsWith(panicCodeId)) {
49+
let panicCode = parseInt(errorString.substring(panicCodeId.length), 16).toString(16);
50+
if (panicCode.length % 2 !== 0) {
51+
panicCode = '0' + panicCode;
52+
}
53+
54+
if (['00', '01'].includes(panicCode)) {
55+
return ''; // For backwards compatibility;
56+
}
57+
return 'panic code 0x' + panicCode;
58+
}
1959

20-
if (!errorString?.startsWith(errorMethodId)) return '';
21-
return toUtf8String('0x' + errorString.substring(138))
22-
.replace(/\x00/g, ''); // Trim null characters.
60+
return '';
2361
};
2462

2563
export const appendRevertString = async (etherProvider: providers.Web3Provider, receipt: any) => {

0 commit comments

Comments
 (0)
Please sign in to comment.