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