@ethereum-waffle/chai
Version:
A sweet set of chai matchers for your blockchain testing needs.
129 lines • 6.86 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.supportRevertedWith = void 0;
const provider_1 = require("@ethereum-waffle/provider");
const ethers_1 = require("ethers");
const call_promise_1 = require("../call-promise");
const json_bigint_1 = __importDefault(require("json-bigint"));
function supportRevertedWith(Assertion) {
Assertion.addMethod('revertedWith', function (revertReason) {
(0, call_promise_1.callPromise)(this);
const assertNotReverted = () => this.assert(false, 'Expected transaction to be reverted', 'Expected transaction NOT to be reverted', 'Transaction reverted.', 'Transaction NOT reverted.');
const onError = (error) => {
var _a, _b, _c, _d;
const revertString = (_d = (_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.receipt) === null || _a === void 0 ? void 0 : _a.revertString) !== null && _b !== void 0 ? _b : decodeHardhatError(error, this)) !== null && _c !== void 0 ? _c : decodeOptimismError(error)) !== null && _d !== void 0 ? _d : (0, provider_1.decodeRevertString)(error);
const isReverted = revertReason instanceof RegExp
? revertReason.test(revertString)
: revertString === revertReason;
this.assert(isReverted, `Expected transaction to be reverted with "${revertReason}", but other reason was found: "${revertString}"`, `Expected transaction NOT to be reverted with "${revertReason}"`, `Transaction reverted with "${revertReason}"`, error);
return error;
};
this.callPromise = this.callPromise.then(assertNotReverted, onError);
this.then = this.callPromise.then.bind(this.callPromise);
this.catch = this.callPromise.catch.bind(this.callPromise);
this.txMatcher = 'revertedWith';
return this;
});
}
exports.supportRevertedWith = supportRevertedWith;
const errorInterface = new ethers_1.ethers.utils.Interface(['function Error(string)']);
const decodeHardhatError = (error, context) => {
var _a, _b, _c;
const tryDecode = (error) => {
if (error === undefined) {
return undefined;
}
if ((error === null || error === void 0 ? void 0 : error.errorName) &&
/**
* Preserve old behaviour for non-custom errors,
* because if the case of regular errors,
* with revertedWith we match against the argument of error (single string),
* not against the error name like in the case of custom errors - because it is always just Error.
* We don't want to require the user to do `expect(tx).to.be.revertedWith('Error').withArgs('Require cause')`.
*/
(error === null || error === void 0 ? void 0 : error.errorName) !== 'Error' &&
error.errorArgs) {
context.args = [error.errorArgs];
context.txErrorName = error.errorName;
return error.errorName;
}
if (error === null || error === void 0 ? void 0 : error.data) {
try {
const decodedReason = errorInterface.decodeFunctionData('Error', error.data);
if (decodedReason[0])
return decodedReason[0];
}
catch (_a) { }
}
const errorString = String(error);
{
// eslint-disable-next-line max-len
const regexp = /VM Exception while processing transaction: reverted with custom error '([a-zA-Z0-9$_]+)\((.*)\)'/g;
const matches = regexp.exec(errorString);
if (matches && matches.length >= 1) {
// Matches is in a format of string: "arg1, arg2, arg3, ..."
// So it only makes sense in an array:
const matchesList = `[${matches[2]}]`;
// Next, it needs to be wrapped in a list to be consistent with the emit matcher:
context.args = [
// Additionally, we preserve numbers as strings,
// otherwise we face an overflow of bignumber.
(0, json_bigint_1.default)({ storeAsString: true }).parse(matchesList)
];
const errorName = matches[1];
context.txErrorName = errorName;
return errorName;
}
}
{
const regexp = new RegExp('VM Exception while processing transaction: reverted with panic code ([a-zA-Z0-9]*)');
const matches = regexp.exec(errorString);
if (matches && matches.length >= 1) {
return 'panic code ' + matches[1];
}
}
{
const regexp = new RegExp('Error: Transaction reverted: (.*)');
const matches = regexp.exec(errorString);
if (matches && matches.length >= 1) {
return matches[1];
}
}
{
const regexp = /revert(ed)? with reason (string )?("(?:[^\\"]|\\.)*")/;
const matches = regexp.exec(errorString);
if (matches && matches.length >= 1) {
return JSON.parse(matches[matches.length - 1]); // parse escapes
}
}
{
const regexp = new RegExp('revert(ed)? with reason (string )?\'(.*)\'');
const matches = regexp.exec(errorString);
if (matches && matches.length >= 1) {
return matches[matches.length - 1];
}
}
return undefined;
};
return (_c = (_b = tryDecode((_a = error.error) === null || _a === void 0 ? void 0 : _a.error)) !== null && _b !== void 0 ? _b : tryDecode(error.error)) !== null && _c !== void 0 ? _c : tryDecode(error); // the error may be wrapped
};
const decodeOptimismError = (error) => {
var _a, _b, _c;
const tryDecode = (error) => {
var _a, _b;
const body = error === null || error === void 0 ? void 0 : error.body;
if (body) {
const errorString = (_b = (_a = JSON.parse(body)) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.message;
const regexp = /execution reverted: (.*)/g;
const matches = regexp.exec(errorString);
if (matches && matches.length >= 1) {
return matches[1];
}
}
};
return (_b = (_a = tryDecode(error)) !== null && _a !== void 0 ? _a : tryDecode(error === null || error === void 0 ? void 0 : error.error)) !== null && _b !== void 0 ? _b : tryDecode((_c = error === null || error === void 0 ? void 0 : error.error) === null || _c === void 0 ? void 0 : _c.error);
};
//# sourceMappingURL=revertedWith.js.map