protocol/contracts/exchange/test/lib_exchange_rich_error_decoder.ts

298 lines
8.7 KiB
TypeScript

import {
addressUtils,
chaiSetup,
OrderStatus,
orderUtils,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { ExchangeRevertErrors, generatePseudoRandomSalt } from '@0x/order-utils';
import { RevertError } from '@0x/utils';
import * as chai from 'chai';
import * as crypto from 'crypto';
import * as _ from 'lodash';
import {
artifacts,
TestLibExchangeRichErrorDecoderContract,
} from '../src';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('LibExchangeRichErrorDecoder', () => {
const SIGNATURE_LENGTH = 66;
const ASSET_DATA_LENGTH = 36;
const ERROR_DATA_LENGTH = 100;
let decoder: TestLibExchangeRichErrorDecoderContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
decoder = await TestLibExchangeRichErrorDecoderContract.deployFrom0xArtifactAsync(
artifacts.TestLibExchangeRichErrorDecoder,
provider,
txDefaults,
);
});
function generateRandomBytes(length: number): string {
const bytes = crypto.randomBytes(length).toString('hex');
return `0x${bytes}`;
}
function createDecodeTest(
revertType: new(...args: any[]) => RevertError,
parameters: any[],
) {
const revert = new revertType(...parameters);
const encoded = revert.encode();
// Exploit the fact that `RevertError` types have the same names as their
// Solidity counterparts.
const endpointName = `decode${revert.name}`;
const callAsync = (encoded: string) => {
return (decoder as any)[endpointName].callAsync.call(
(decoder as any)[endpointName],
encoded,
);
};
describe(`${endpointName}()`, async () => {
it('decodes encoded parameters', async () => {
let results = await callAsync(encoded);
if (!_.isArray(results)) {
results = [results];
}
return expect(results).to.deep.equal(parameters);
});
it('reverts if selector does not match', async () => {
// Replace the selector with null bytes.
const NULL_SELECTOR = '00000000';
const withBadSelector = `0x${NULL_SELECTOR}${encoded.substr(10)}`;
return expect(callAsync(withBadSelector)).to.revertWith('BAD_SELECTOR');
});
});
};
(() => {
const errorCode = ExchangeRevertErrors.SignatureErrorCode.Illegal;
const orderHash = orderUtils.generatePseudoRandomOrderHash();
const signer = addressUtils.generatePseudoRandomAddress();
const signature = generateRandomBytes(SIGNATURE_LENGTH);
const errorData = generateRandomBytes(ERROR_DATA_LENGTH);
createDecodeTest(
ExchangeRevertErrors.SignatureError,
[
errorCode,
orderHash,
signer,
signature,
],
);
createDecodeTest(
ExchangeRevertErrors.SignatureValidatorError,
[
orderHash,
signer,
signature,
errorData,
],
);
createDecodeTest(
ExchangeRevertErrors.SignatureWalletError,
[
orderHash,
signer,
signature,
errorData,
],
);
createDecodeTest(
ExchangeRevertErrors.SignatureOrderValidatorError,
[
orderHash,
signer,
signature,
errorData,
],
);
createDecodeTest(
ExchangeRevertErrors.SignatureWalletOrderValidatorError,
[
orderHash,
signer,
signature,
errorData,
],
);
})();
(() => {
const orderHash = orderUtils.generatePseudoRandomOrderHash();
const orderStatus = OrderStatus.FullyFilled;
createDecodeTest(
ExchangeRevertErrors.OrderStatusError,
[
orderHash,
orderStatus,
],
);
})();
(() => {
const orderHash = orderUtils.generatePseudoRandomOrderHash();
const address = addressUtils.generatePseudoRandomAddress();
createDecodeTest(
ExchangeRevertErrors.InvalidSenderError,
[
orderHash,
address,
],
);
createDecodeTest(
ExchangeRevertErrors.InvalidMakerError,
[
orderHash,
address,
],
);
createDecodeTest(
ExchangeRevertErrors.InvalidTakerError,
[
orderHash,
address,
],
);
})();
(() => {
const errorCode = ExchangeRevertErrors.FillErrorCode.TakerOverpay;
const orderHash = orderUtils.generatePseudoRandomOrderHash();
createDecodeTest(
ExchangeRevertErrors.FillError,
[
errorCode,
orderHash,
],
);
})();
(() => {
const maker = addressUtils.generatePseudoRandomAddress();
const sender = addressUtils.generatePseudoRandomAddress();
const currentEpoch = generatePseudoRandomSalt();
createDecodeTest(
ExchangeRevertErrors.OrderEpochError,
[
maker,
sender,
currentEpoch,
],
);
})();
(() => {
const assetProxyAddress = addressUtils.generatePseudoRandomAddress();
createDecodeTest(
ExchangeRevertErrors.AssetProxyExistsError,
[
assetProxyAddress,
],
);
})();
(() => {
const errorCode = ExchangeRevertErrors.AssetProxyDispatchErrorCode.UnknownAssetProxy;
const orderHash = orderUtils.generatePseudoRandomOrderHash();
const assetData = generateRandomBytes(ASSET_DATA_LENGTH);
createDecodeTest(
ExchangeRevertErrors.AssetProxyDispatchError,
[
errorCode,
orderHash,
assetData,
],
);
})();
(() => {
const orderHash = orderUtils.generatePseudoRandomOrderHash();
const assetData = generateRandomBytes(ASSET_DATA_LENGTH);
const errorData = generateRandomBytes(ERROR_DATA_LENGTH);
createDecodeTest(
ExchangeRevertErrors.AssetProxyTransferError,
[
orderHash,
assetData,
errorData,
],
);
})();
(() => {
const leftOrderHash = orderUtils.generatePseudoRandomOrderHash();
const rightOrderHash = orderUtils.generatePseudoRandomOrderHash();
createDecodeTest(
ExchangeRevertErrors.NegativeSpreadError,
[
leftOrderHash,
rightOrderHash,
],
);
})();
(() => {
const errorCode = ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted;
const transactionHash = orderUtils.generatePseudoRandomOrderHash();
createDecodeTest(
ExchangeRevertErrors.TransactionError,
[
errorCode,
transactionHash,
],
);
})();
(() => {
const transactionHash = orderUtils.generatePseudoRandomOrderHash();
const signer = addressUtils.generatePseudoRandomAddress();
const signature = generateRandomBytes(SIGNATURE_LENGTH);
createDecodeTest(
ExchangeRevertErrors.TransactionSignatureError,
[
transactionHash,
signer,
signature,
],
);
})();
(() => {
const transactionHash = orderUtils.generatePseudoRandomOrderHash();
const errorData = generateRandomBytes(ERROR_DATA_LENGTH);
createDecodeTest(
ExchangeRevertErrors.TransactionExecutionError,
[
transactionHash,
errorData,
],
);
})();
(() => {
const orderHash = orderUtils.generatePseudoRandomOrderHash();
createDecodeTest(
ExchangeRevertErrors.IncompleteFillError,
[
orderHash,
],
);
})();
});