In @0x/utils
: Add AnyRevertError
type that matches with any revert error
This commit is contained in:
parent
abb71cd074
commit
703a0fde3c
@ -15,7 +15,7 @@
|
||||
"pr": 1742
|
||||
},
|
||||
{
|
||||
"note": "Add `RevertError` and `StringRevertError` types and associated utilities",
|
||||
"note": "Add `RevertError`, `StringRevertError`, `AnyRevertError` types and associated utilities",
|
||||
"pr": TODO
|
||||
}
|
||||
],
|
||||
|
@ -15,4 +15,10 @@ export { signTypedDataUtils } from './sign_typed_data_utils';
|
||||
export import AbiEncoder = require('./abi_encoder');
|
||||
export * from './types';
|
||||
export { generatePseudoRandom256BitNumber } from './random';
|
||||
export { decodeRevertError, registerRevertErrorType, RevertError, StringRevertError } from './revert_error';
|
||||
export {
|
||||
decodeRevertError,
|
||||
registerRevertErrorType,
|
||||
RevertError,
|
||||
StringRevertError,
|
||||
AnyRevertError,
|
||||
} from './revert_error';
|
||||
|
@ -47,7 +47,7 @@ export function decodeRevertError(bytes: string | Buffer): RevertError {
|
||||
export abstract class RevertError extends Error {
|
||||
// Map of types registered via `registerType`.
|
||||
private static readonly _typeRegistry: ObjectMap<RevertErrorRegistryItem> = {};
|
||||
public abi: RevertErrorAbi;
|
||||
public abi?: RevertErrorAbi;
|
||||
public values: ValueMap = {};
|
||||
|
||||
/**
|
||||
@ -82,6 +82,9 @@ export abstract class RevertError extends Error {
|
||||
if (instance.selector in RevertError._typeRegistry) {
|
||||
throw new Error(`RevertError type with signature "${instance.signature}" is already registered`);
|
||||
}
|
||||
if (_.isNil(instance.abi)) {
|
||||
throw new Error(`Attempting to register a RevertError class with no ABI`);
|
||||
}
|
||||
RevertError._typeRegistry[instance.selector] = {
|
||||
type: revertClass,
|
||||
decoder: createDecoder(instance.abi),
|
||||
@ -102,11 +105,13 @@ export abstract class RevertError extends Error {
|
||||
* @param declaration Function-style declaration of the revert (e.g., Error(string message))
|
||||
* @param values Optional mapping of parameters to values.
|
||||
*/
|
||||
protected constructor(declaration: string, values?: ValueMap) {
|
||||
protected constructor(declaration?: string, values?: ValueMap) {
|
||||
super();
|
||||
this.abi = declarationToAbi(declaration);
|
||||
if (values !== undefined) {
|
||||
_.assign(this.values, _.cloneDeep(values));
|
||||
if (declaration !== undefined) {
|
||||
this.abi = declarationToAbi(declaration);
|
||||
if (values !== undefined) {
|
||||
_.assign(this.values, _.cloneDeep(values));
|
||||
}
|
||||
}
|
||||
// Extending Error is tricky; we need to explicitly set the prototype.
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
@ -117,28 +122,40 @@ export abstract class RevertError extends Error {
|
||||
* Get the ABI name for this revert.
|
||||
*/
|
||||
get name(): string {
|
||||
return this.abi.name;
|
||||
if (!_.isNil(this.abi)) {
|
||||
return this.abi.name;
|
||||
}
|
||||
return '<AnyRevertError>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hex selector for this revert (without leading '0x').
|
||||
*/
|
||||
get selector(): string {
|
||||
return toSelector(this.abi);
|
||||
if (!_.isNil(this.abi)) {
|
||||
return toSelector(this.abi);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the signature for this revert: e.g., 'Error(string)'.
|
||||
*/
|
||||
get signature(): string {
|
||||
return toSignature(this.abi);
|
||||
if (!_.isNil(this.abi)) {
|
||||
return toSignature(this.abi);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ABI arguments for this revert.
|
||||
*/
|
||||
get arguments(): DataItem[] {
|
||||
return this.abi.arguments || [];
|
||||
if (!_.isNil(this.abi)) {
|
||||
return this.abi.arguments || [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,9 +173,18 @@ export abstract class RevertError extends Error {
|
||||
if (typeof _other === 'string') {
|
||||
_other = RevertError.decode(_other);
|
||||
}
|
||||
if (!(_other instanceof RevertError)) {
|
||||
return false;
|
||||
}
|
||||
// If either is of the `AnyRevertError` type, always succeed.
|
||||
if (this._isAnyType || _other._isAnyType) {
|
||||
return true;
|
||||
}
|
||||
// Must be of same type.
|
||||
if (this.constructor !== _other.constructor) {
|
||||
return false;
|
||||
}
|
||||
// Must share the same parameter values if defined in both instances.
|
||||
for (const name of Object.keys(this.values)) {
|
||||
const a = this.values[name];
|
||||
const b = _other.values[name];
|
||||
@ -188,14 +214,30 @@ export abstract class RevertError extends Error {
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
private get _isAnyType(): boolean {
|
||||
return _.isNil(this.abi);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RevertError type for standard string reverts.
|
||||
*/
|
||||
export class StringRevertError extends RevertError {
|
||||
constructor(message?: string) {
|
||||
super('Error(string message)', { message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special RevertError type that matches with any other RevertError instance.
|
||||
*/
|
||||
export class AnyRevertError extends RevertError {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a solidity function declaration into a RevertErrorAbi object.
|
||||
* @param declaration Function declaration (e.g., 'foo(uint256 bar)').
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { RevertError, StringRevertError } from '../src/revert_error';
|
||||
import { AnyRevertError, RevertError, StringRevertError } from '../src/revert_error';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
|
||||
@ -35,6 +35,11 @@ describe('RevertError', () => {
|
||||
const revert2 = new StringRevertError();
|
||||
expect(revert1.equals(revert2)).to.be.true();
|
||||
});
|
||||
it('should equate AnyRevertError with a real RevertError', () => {
|
||||
const revert1 = new StringRevertError(message);
|
||||
const revert2 = new AnyRevertError();
|
||||
expect(revert1.equals(revert2)).to.be.true();
|
||||
});
|
||||
it('should not equate a the same RevertError type with different values', () => {
|
||||
const revert1 = new StringRevertError(message);
|
||||
const revert2 = new StringRevertError(`${message}1`);
|
||||
|
Loading…
x
Reference in New Issue
Block a user