`@0x/contracts-exchange-libs: Appease the linter and prettier gods.

This commit is contained in:
Lawrence Forman 2019-08-02 13:30:48 -04:00
parent 4711ce5532
commit 6345faa4a9
20 changed files with 334 additions and 465 deletions

View File

@ -3,18 +3,12 @@ import { LibMathRevertErrors } from '@0x/order-utils';
import { FillResults } from '@0x/types';
import { BigNumber } from '@0x/utils';
const {
safeAdd,
safeSub,
safeMul,
safeDiv,
} = ReferenceFunctions;
const { safeAdd, safeSub, safeMul, safeDiv } = ReferenceFunctions;
export function isRoundingErrorFloor(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): boolean {
/**
* Checks if rounding error >= 0.1% when rounding down.
*/
export function isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
if (denominator.eq(0)) {
throw new LibMathRevertErrors.DivisionByZeroError();
}
@ -28,11 +22,10 @@ export function isRoundingErrorFloor(
return lhs.gte(rhs);
}
export function isRoundingErrorCeil(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): boolean {
/**
* Checks if rounding error >= 0.1% when rounding up.
*/
export function isRoundingErrorCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
if (denominator.eq(0)) {
throw new LibMathRevertErrors.DivisionByZeroError();
}
@ -47,66 +40,46 @@ export function isRoundingErrorCeil(
return lhs.gte(rhs);
}
export function safeGetPartialAmountFloor(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): BigNumber {
/**
* Calculates partial value given a numerator and denominator rounded down.
* Reverts if rounding error is >= 0.1%
*/
export function safeGetPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
if (isRoundingErrorFloor(numerator, denominator, target)) {
throw new LibMathRevertErrors.RoundingError(numerator, denominator, target);
}
return safeDiv(
safeMul(numerator, target),
denominator,
);
return safeDiv(safeMul(numerator, target), denominator);
}
export function safeGetPartialAmountCeil(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): BigNumber {
/**
* Calculates partial value given a numerator and denominator rounded down.
* Reverts if rounding error is >= 0.1%
*/
export function safeGetPartialAmountCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
if (isRoundingErrorCeil(numerator, denominator, target)) {
throw new LibMathRevertErrors.RoundingError(numerator, denominator, target);
}
return safeDiv(
safeAdd(
safeMul(numerator, target),
safeSub(denominator, new BigNumber(1)),
),
denominator,
);
return safeDiv(safeAdd(safeMul(numerator, target), safeSub(denominator, new BigNumber(1))), denominator);
}
export function getPartialAmountFloor(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): BigNumber {
return safeDiv(
safeMul(numerator, target),
denominator,
);
/**
* Calculates partial value given a numerator and denominator rounded down.
*/
export function getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
return safeDiv(safeMul(numerator, target), denominator);
}
export function getPartialAmountCeil(
numerator: BigNumber,
denominator: BigNumber,
target: BigNumber,
): BigNumber {
return safeDiv(
safeAdd(
safeMul(numerator, target),
safeSub(denominator, new BigNumber(1)),
),
denominator,
);
/**
* Calculates partial value given a numerator and denominator rounded down.
*/
export function getPartialAmountCeil(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
return safeDiv(safeAdd(safeMul(numerator, target), safeSub(denominator, new BigNumber(1))), denominator);
}
export function addFillResults(
a: FillResults,
b: FillResults,
): FillResults {
/**
* Adds properties of two `FillResults`.
*/
export function addFillResults(a: FillResults, b: FillResults): FillResults {
return {
makerAssetFilledAmount: safeAdd(a.makerAssetFilledAmount, b.makerAssetFilledAmount),
takerAssetFilledAmount: safeAdd(a.takerAssetFilledAmount, b.takerAssetFilledAmount),

View File

@ -1,9 +1,4 @@
import {
blockchainTests,
constants,
describe,
expect,
} from '@0x/contracts-test-utils';
import { blockchainTests, constants, describe, expect } from '@0x/contracts-test-utils';
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
import * as _ from 'lodash';
@ -41,58 +36,54 @@ blockchainTests('LibFillResults', env => {
];
it('matches the output of the reference function', async () => {
const [ a, b ] = DEFAULT_FILL_RESULTS;
const [a, b] = DEFAULT_FILL_RESULTS;
const expected = ReferenceFunctions.addFillResults(a, b);
const actual = await libsContract.addFillResults.callAsync(a, b);
expect(actual).to.deep.equal(expected);
});
it('reverts if computing `makerAssetFilledAmount` overflows', async () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.makerAssetFilledAmount = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
a.makerAssetFilledAmount,
b.makerAssetFilledAmount,
);
return expect(libsContract.addFillResults.callAsync(a, b))
.to.revertWith(expectedError);
return expect(libsContract.addFillResults.callAsync(a, b)).to.revertWith(expectedError);
});
it('reverts if computing `takerAssetFilledAmount` overflows', async () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.takerAssetFilledAmount = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
a.takerAssetFilledAmount,
b.takerAssetFilledAmount,
);
return expect(libsContract.addFillResults.callAsync(a, b))
.to.revertWith(expectedError);
return expect(libsContract.addFillResults.callAsync(a, b)).to.revertWith(expectedError);
});
it('reverts if computing `makerFeePaid` overflows', async () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.makerFeePaid = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
a.makerFeePaid,
b.makerFeePaid,
);
return expect(libsContract.addFillResults.callAsync(a, b))
.to.revertWith(expectedError);
return expect(libsContract.addFillResults.callAsync(a, b)).to.revertWith(expectedError);
});
it('reverts if computing `takerFeePaid` overflows', async () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.takerFeePaid = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
a.takerFeePaid,
b.takerFeePaid,
);
return expect(libsContract.addFillResults.callAsync(a, b))
.to.revertWith(expectedError);
return expect(libsContract.addFillResults.callAsync(a, b)).to.revertWith(expectedError);
});
});
});

View File

@ -26,17 +26,13 @@ blockchainTests('LibMath', env => {
});
// Wrap a reference function with identical arguments in a promise.
function createAsyncReferenceFunction<T>(
ref: (...args: any[]) => T,
): (...args: any[]) => Promise<T> {
function createAsyncReferenceFunction<T>(ref: (...args: any[]) => T): (...args: any[]) => Promise<T> {
return async (...args: any[]): Promise<T> => {
return ref(...args);
};
}
function createContractTestFunction<T>(
name: string,
): (...args: any[]) => Promise<T> {
function createContractTestFunction<T>(name: string): (...args: any[]) => Promise<T> {
return async (...args: any[]): Promise<T> => {
const method = (libsContract as any)[name] as { callAsync: (...args: any[]) => Promise<T> };
return method.callAsync(...args);
@ -72,8 +68,9 @@ blockchainTests('LibMath', env => {
numerator.times(target),
denominator,
);
return expect(libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `numerator * target` overflows', async () => {
@ -85,8 +82,9 @@ blockchainTests('LibMath', env => {
numerator,
target,
);
return expect(libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
});
});
@ -121,8 +119,9 @@ blockchainTests('LibMath', env => {
denominator,
new BigNumber(1),
);
return expect(libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `numerator * target` overflows', async () => {
@ -134,8 +133,9 @@ blockchainTests('LibMath', env => {
numerator,
target,
);
return expect(libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
});
});
@ -164,13 +164,10 @@ blockchainTests('LibMath', env => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
const expectedError = new LibMathRevertErrors.RoundingError(
numerator,
denominator,
target,
);
return expect(libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
const expectedError = new LibMathRevertErrors.RoundingError(numerator, denominator, target);
return expect(
libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `denominator` is zero', async () => {
@ -178,8 +175,9 @@ blockchainTests('LibMath', env => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `numerator * target` overflows', async () => {
@ -191,8 +189,9 @@ blockchainTests('LibMath', env => {
numerator,
target,
);
return expect(libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
});
});
@ -221,13 +220,10 @@ blockchainTests('LibMath', env => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
const expectedError = new LibMathRevertErrors.RoundingError(
numerator,
denominator,
target,
);
return expect(libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
const expectedError = new LibMathRevertErrors.RoundingError(numerator, denominator, target);
return expect(
libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `denominator` is zero', async () => {
@ -235,8 +231,9 @@ blockchainTests('LibMath', env => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `numerator * target` overflows', async () => {
@ -248,8 +245,9 @@ blockchainTests('LibMath', env => {
numerator,
target,
);
return expect(libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
});
});
@ -269,6 +267,7 @@ blockchainTests('LibMath', env => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
// tslint:disable-next-line: boolean-naming
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
expect(actual).to.eq(true);
});
@ -277,6 +276,7 @@ blockchainTests('LibMath', env => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(5e2);
// tslint:disable-next-line: boolean-naming
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
expect(actual).to.eq(false);
});
@ -285,7 +285,9 @@ blockchainTests('LibMath', env => {
const numerator = ONE_ETHER;
const denominator = ONE_ETHER.dividedToIntegerBy(2);
const target = ONE_ETHER.times(0.01);
// tslint:disable-next-line: boolean-naming
const expected = ReferenceFunctions.isRoundingErrorFloor(numerator, denominator, target);
// tslint:disable-next-line: boolean-naming
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
expect(actual).to.eq(expected);
});
@ -295,8 +297,9 @@ blockchainTests('LibMath', env => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
it('reverts if `numerator * target` overflows', async () => {
@ -308,8 +311,9 @@ blockchainTests('LibMath', env => {
numerator,
target,
);
return expect(libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(
libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target),
).to.revertWith(expectedError);
});
});
});
@ -329,7 +333,8 @@ blockchainTests('LibMath', env => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
// tslint:disable-next-line: boolean-naming
const actual = await libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target);
expect(actual).to.eq(true);
});
@ -337,7 +342,8 @@ blockchainTests('LibMath', env => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(5e2);
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
// tslint:disable-next-line: boolean-naming
const actual = await libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target);
expect(actual).to.eq(false);
});
@ -345,7 +351,9 @@ blockchainTests('LibMath', env => {
const numerator = ONE_ETHER;
const denominator = ONE_ETHER.dividedToIntegerBy(2);
const target = ONE_ETHER.times(0.01);
// tslint:disable-next-line: boolean-naming
const expected = ReferenceFunctions.isRoundingErrorCeil(numerator, denominator, target);
// tslint:disable-next-line: boolean-naming
const actual = await libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target);
expect(actual).to.eq(expected);
});
@ -355,8 +363,9 @@ blockchainTests('LibMath', env => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target)).to.revertWith(
expectedError,
);
});
it('reverts if `numerator * target` overflows', async () => {
@ -368,8 +377,9 @@ blockchainTests('LibMath', env => {
numerator,
target,
);
return expect(libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target))
.to.revertWith(expectedError);
return expect(libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target)).to.revertWith(
expectedError,
);
});
});
});

View File

@ -1,8 +1,4 @@
import {
constants,
describe,
expect,
} from '@0x/contracts-test-utils';
import { constants, describe, expect } from '@0x/contracts-test-utils';
import { LibMathRevertErrors } from '@0x/order-utils';
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
import * as _ from 'lodash';
@ -20,7 +16,6 @@ import {
describe('Reference Functions', () => {
const { ONE_ETHER, MAX_UINT256, MAX_UINT256_ROOT, ZERO_AMOUNT } = constants;
describe('LibFillResults', () => {
describe('addFillResults', () => {
const DEFAULT_FILL_RESULTS = [
{
@ -38,7 +33,7 @@ describe('Reference Functions', () => {
];
it('reverts if computing `makerAssetFilledAmount` overflows', () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.makerAssetFilledAmount = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
@ -49,7 +44,7 @@ describe('Reference Functions', () => {
});
it('reverts if computing `takerAssetFilledAmount` overflows', () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.takerAssetFilledAmount = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
@ -60,7 +55,7 @@ describe('Reference Functions', () => {
});
it('reverts if computing `makerFeePaid` overflows', () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.makerFeePaid = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
@ -71,7 +66,7 @@ describe('Reference Functions', () => {
});
it('reverts if computing `takerFeePaid` overflows', () => {
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
const [a, b] = _.cloneDeep(DEFAULT_FILL_RESULTS);
b.takerFeePaid = MAX_UINT256;
const expectedError = new SafeMathRevertErrors.SafeMathError(
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
@ -95,8 +90,9 @@ describe('Reference Functions', () => {
numerator.times(target),
denominator,
);
return expect(() => getPartialAmountFloor(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => getPartialAmountFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
it('reverts if `numerator * target` overflows', () => {
@ -108,8 +104,9 @@ describe('Reference Functions', () => {
numerator,
target,
);
return expect(() => getPartialAmountFloor(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => getPartialAmountFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
});
});
@ -126,8 +123,9 @@ describe('Reference Functions', () => {
denominator,
new BigNumber(1),
);
return expect(() => getPartialAmountCeil(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => getPartialAmountCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
it('reverts if `numerator * target` overflows', () => {
@ -139,8 +137,9 @@ describe('Reference Functions', () => {
numerator,
target,
);
return expect(() => getPartialAmountCeil(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => getPartialAmountCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
});
});
@ -151,13 +150,10 @@ describe('Reference Functions', () => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
const expectedError = new LibMathRevertErrors.RoundingError(
numerator,
denominator,
target,
const expectedError = new LibMathRevertErrors.RoundingError(numerator, denominator, target);
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target))
.to.throw(expectedError.message);
});
it('reverts if `denominator` is zero', () => {
@ -165,8 +161,9 @@ describe('Reference Functions', () => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
it('reverts if `numerator * target` overflows', () => {
@ -178,8 +175,9 @@ describe('Reference Functions', () => {
numerator,
target,
);
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
});
});
@ -190,13 +188,10 @@ describe('Reference Functions', () => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
const expectedError = new LibMathRevertErrors.RoundingError(
numerator,
denominator,
target,
const expectedError = new LibMathRevertErrors.RoundingError(numerator, denominator, target);
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target))
.to.throw(expectedError.message);
});
it('reverts if `denominator` is zero', () => {
@ -204,8 +199,9 @@ describe('Reference Functions', () => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
it('reverts if `numerator * target` overflows', () => {
@ -217,8 +213,9 @@ describe('Reference Functions', () => {
numerator,
target,
);
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
});
});
@ -229,6 +226,7 @@ describe('Reference Functions', () => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
// tslint:disable-next-line: boolean-naming
const actual = isRoundingErrorFloor(numerator, denominator, target);
expect(actual).to.eq(true);
});
@ -237,6 +235,7 @@ describe('Reference Functions', () => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(5e2);
// tslint:disable-next-line: boolean-naming
const actual = isRoundingErrorFloor(numerator, denominator, target);
expect(actual).to.eq(false);
});
@ -246,8 +245,9 @@ describe('Reference Functions', () => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => isRoundingErrorFloor(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => isRoundingErrorFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
it('reverts if `numerator * target` overflows', () => {
@ -259,8 +259,9 @@ describe('Reference Functions', () => {
numerator,
target,
);
return expect(() => isRoundingErrorFloor(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => isRoundingErrorFloor(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
});
});
@ -271,7 +272,8 @@ describe('Reference Functions', () => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(333);
const actual = isRoundingErrorFloor(numerator, denominator, target);
// tslint:disable-next-line: boolean-naming
const actual = isRoundingErrorCeil(numerator, denominator, target);
expect(actual).to.eq(true);
});
@ -279,7 +281,8 @@ describe('Reference Functions', () => {
const numerator = new BigNumber(1e3);
const denominator = new BigNumber(1e4);
const target = new BigNumber(5e2);
const actual = isRoundingErrorFloor(numerator, denominator, target);
// tslint:disable-next-line: boolean-naming
const actual = isRoundingErrorCeil(numerator, denominator, target);
expect(actual).to.eq(false);
});
@ -288,8 +291,9 @@ describe('Reference Functions', () => {
const denominator = ZERO_AMOUNT;
const target = ONE_ETHER.times(0.01);
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => isRoundingErrorCeil(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => isRoundingErrorCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
it('reverts if `numerator * target` overflows', () => {
@ -301,8 +305,9 @@ describe('Reference Functions', () => {
numerator,
target,
);
return expect(() => isRoundingErrorCeil(numerator, denominator, target))
.to.throw(expectedError.message);
return expect(() => isRoundingErrorCeil(numerator, denominator, target)).to.throw(
expectedError.message,
);
});
});
});

View File

@ -33,10 +33,10 @@
"src/interfaces/IExchangeCore.sol",
"src/interfaces/IMatchOrders.sol",
"src/interfaces/ISignatureValidator.sol",
"test/IsolatedExchange.sol",
"src/interfaces/ITransactions.sol",
"src/interfaces/IWallet.sol",
"src/interfaces/IWrapperFunctions.sol",
"test/IsolatedExchange.sol",
"test/ReentrantERC20Token.sol",
"test/TestAssetProxyDispatcher.sol",
"test/TestExchangeInternals.sol",

View File

@ -64,7 +64,7 @@ contract IsolatedExchange is
// Fail if the first byte is 0.
if (assetData.length > 0 && assetData[0] == 0x00) {
revert('TRANSFER_FAILED');
revert("TRANSFER_FAILED");
}
}

View File

@ -4,25 +4,17 @@ import { BigNumber } from '@0x/utils';
const { safeGetPartialAmountFloor } = ExchangeLibsReferenceFunctions;
export function calculateFillResults(
order: OrderWithoutDomain,
takerAssetFilledAmount: BigNumber,
): FillResults {
/**
* Calculates amounts filled and fees paid by maker and taker.
*/
export function calculateFillResults(order: OrderWithoutDomain, takerAssetFilledAmount: BigNumber): FillResults {
const makerAssetFilledAmount = safeGetPartialAmountFloor(
takerAssetFilledAmount,
order.takerAssetAmount,
order.makerAssetAmount,
);
const makerFeePaid = safeGetPartialAmountFloor(
makerAssetFilledAmount,
order.makerAssetAmount,
order.makerFee,
);
const takerFeePaid = safeGetPartialAmountFloor(
takerAssetFilledAmount,
order.takerAssetAmount,
order.takerFee,
);
const makerFeePaid = safeGetPartialAmountFloor(makerAssetFilledAmount, order.makerAssetAmount, order.makerFee);
const takerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.takerFee);
return {
makerAssetFilledAmount,
takerAssetFilledAmount,

View File

@ -19,8 +19,8 @@ import {
artifacts,
ReferenceFunctions,
TestExchangeInternalsContract,
TestExchangeInternalsFillEventArgs,
TestExchangeInternalsDispatchTransferFromCalledEventArgs,
TestExchangeInternalsFillEventArgs,
} from '../src';
blockchainTests('Exchange core internal functions', env => {
@ -50,7 +50,7 @@ blockchainTests('Exchange core internal functions', env => {
let senderAddress: string;
before(async () => {
[ senderAddress ] = await env.getAccountAddressesAsync();
[senderAddress] = await env.getAccountAddressesAsync();
testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
artifacts.TestExchangeInternals,
env.provider,
@ -114,11 +114,7 @@ blockchainTests('Exchange core internal functions', env => {
describe('explicit tests', () => {
const MAX_UINT256_ROOT = constants.MAX_UINT256_ROOT;
function makeOrder(details?: Partial<Order>): Order {
return _.assign(
{},
EMPTY_ORDER,
details,
);
return _.assign({}, EMPTY_ORDER, details);
}
it('matches the output of the reference function', async () => {
@ -146,8 +142,9 @@ blockchainTests('Exchange core internal functions', env => {
takerAssetFilledAmount,
order.makerAssetAmount,
);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if computing `fillResults.makerFeePaid` overflows', async () => {
@ -168,8 +165,9 @@ blockchainTests('Exchange core internal functions', env => {
makerAssetFilledAmount,
order.makerFee,
);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if computing `fillResults.takerFeePaid` overflows', async () => {
@ -185,8 +183,9 @@ blockchainTests('Exchange core internal functions', env => {
takerAssetFilledAmount,
order.takerFee,
);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if `order.makerAssetAmount` is 0', async () => {
@ -196,8 +195,9 @@ blockchainTests('Exchange core internal functions', env => {
});
const takerAssetFilledAmount = ONE_ETHER;
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if `order.takerAssetAmount` is 0', async () => {
@ -207,8 +207,9 @@ blockchainTests('Exchange core internal functions', env => {
});
const takerAssetFilledAmount = ONE_ETHER;
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', async () => {
@ -222,8 +223,9 @@ blockchainTests('Exchange core internal functions', env => {
order.takerAssetAmount,
order.makerAssetAmount,
);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if there is a rounding error computing `makerFeePaid`', async () => {
@ -243,8 +245,9 @@ blockchainTests('Exchange core internal functions', env => {
order.makerAssetAmount,
order.makerFee,
);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
it('reverts if there is a rounding error computing `takerFeePaid`', async () => {
@ -264,8 +267,9 @@ blockchainTests('Exchange core internal functions', env => {
order.makerAssetAmount,
order.takerFee,
);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount))
.to.revertWith(expectedError);
return expect(testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount)).to.revertWith(
expectedError,
);
});
});
});
@ -299,10 +303,7 @@ blockchainTests('Exchange core internal functions', env => {
takerAssetFillAmount: BigNumber,
): Promise<void> {
const orderHash = randomHash();
const fillResults = ReferenceFunctions.calculateFillResults(
order,
takerAssetFillAmount,
);
const fillResults = ReferenceFunctions.calculateFillResults(order, takerAssetFillAmount);
const expectedFilledState = orderTakerAssetFilledAmount.plus(takerAssetFillAmount);
// CAll `testUpdateFilledState()`, which will set the `filled`
// state for this order to `orderTakerAssetFilledAmount` before
@ -321,6 +322,7 @@ blockchainTests('Exchange core internal functions', env => {
// Assert the `filled` state for this order.
expect(actualFilledState).to.bignumber.eq(expectedFilledState);
// Assert the logs.
// tslint:disable-next-line: no-unnecessary-type-assertion
const fillEvent = receipt.logs[0] as LogWithDecodedArgs<TestExchangeInternalsFillEventArgs>;
expect(fillEvent.event).to.eq('Fill');
expect(fillEvent.args.makerAddress).to.eq(order.makerAddress);
@ -363,13 +365,15 @@ blockchainTests('Exchange core internal functions', env => {
orderTakerAssetFilledAmount,
takerAssetFillAmount,
);
return expect(testExchange.testUpdateFilledState.awaitTransactionSuccessAsync(
order,
randomAddress(),
randomHash(),
orderTakerAssetFilledAmount,
fillResults,
)).to.revertWith(expectedError);
return expect(
testExchange.testUpdateFilledState.awaitTransactionSuccessAsync(
order,
randomAddress(),
randomHash(),
orderTakerAssetFilledAmount,
fillResults,
),
).to.revertWith(expectedError);
});
});
@ -402,14 +406,11 @@ blockchainTests('Exchange core internal functions', env => {
takerFeePaid: ONE_ETHER.times(0.025),
};
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
await testExchange.settleOrder.sendTransactionAsync(
orderHash,
order,
takerAddress,
fillResults,
),
await testExchange.settleOrder.sendTransactionAsync(orderHash, order, takerAddress, fillResults),
);
const logs = receipt.logs as Array<LogWithDecodedArgs<TestExchangeInternalsDispatchTransferFromCalledEventArgs>>;
const logs = receipt.logs as Array<
LogWithDecodedArgs<TestExchangeInternalsDispatchTransferFromCalledEventArgs>
>;
expect(logs.length === 4);
expect(_.every(logs, log => log.event === 'DispatchTransferFromCalled')).to.be.true();
// taker -> maker

View File

@ -1,10 +1,5 @@
import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
import {
blockchainTests,
constants,
expect,
hexRandom,
} from '@0x/contracts-test-utils';
import { blockchainTests, constants, expect, hexRandom } from '@0x/contracts-test-utils';
import { ExchangeRevertErrors, LibMathRevertErrors } from '@0x/order-utils';
import { FillResults, OrderInfo, OrderStatus, SignatureType } from '@0x/types';
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
@ -50,7 +45,7 @@ blockchainTests('Isolated fillOrder() tests', env => {
let nextSaltValue = 1;
before(async () => {
[ takerAddress, notTakerAddress ] = await env.getAccountAddressesAsync();
[takerAddress, notTakerAddress] = await env.getAccountAddressesAsync();
exchange = await IsolatedExchangeWrapper.deployAsync(
env.web3Wrapper,
_.assign(env.txDefaults, { from: takerAddress }),
@ -79,14 +74,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
const fillResults = await exchange.fillOrderAsync(order, takerAssetFillAmount, signature);
const newOrderInfo = await exchange.getOrderInfoAsync(order);
// Check returned fillResults.
expect(fillResults.makerAssetFilledAmount)
.to.bignumber.eq(efr.makerAssetFilledAmount);
expect(fillResults.takerAssetFilledAmount)
.to.bignumber.eq(efr.takerAssetFilledAmount);
expect(fillResults.makerFeePaid)
.to.bignumber.eq(efr.makerFeePaid);
expect(fillResults.takerFeePaid)
.to.bignumber.eq(efr.takerFeePaid);
expect(fillResults.makerAssetFilledAmount).to.bignumber.eq(efr.makerAssetFilledAmount);
expect(fillResults.takerAssetFilledAmount).to.bignumber.eq(efr.takerAssetFilledAmount);
expect(fillResults.makerFeePaid).to.bignumber.eq(efr.makerFeePaid);
expect(fillResults.takerFeePaid).to.bignumber.eq(efr.takerFeePaid);
// Check balances.
for (const assetData of Object.keys(efb)) {
for (const address of Object.keys(efb[assetData])) {
@ -98,13 +89,11 @@ blockchainTests('Isolated fillOrder() tests', env => {
}
// Check order info.
expect(newOrderInfo.orderStatus).to.eq(eoi.orderStatus);
expect(newOrderInfo.orderTakerAssetFilledAmount)
.to.bignumber.eq(eoi.orderTakerAssetFilledAmount);
expect(newOrderInfo.orderTakerAssetFilledAmount).to.bignumber.eq(eoi.orderTakerAssetFilledAmount);
// Check that there wasn't an overfill.
expect(
newOrderInfo.orderTakerAssetFilledAmount.lte(order.takerAssetAmount),
'checking for overfill',
).to.be.ok('');
expect(newOrderInfo.orderTakerAssetFilledAmount.lte(order.takerAssetAmount), 'checking for overfill').to.be.ok(
'',
);
return {
fillResults,
orderInfo: newOrderInfo,
@ -116,24 +105,17 @@ blockchainTests('Isolated fillOrder() tests', env => {
orderInfo: OrderInfo,
takerAssetFillAmount: BigNumber,
): FillResults {
const remainingTakerAssetAmount = order.takerAssetAmount.minus(
orderInfo.orderTakerAssetFilledAmount,
);
return calculateFillResults(
order,
BigNumber.min(takerAssetFillAmount, remainingTakerAssetAmount),
);
const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount);
return calculateFillResults(order, BigNumber.min(takerAssetFillAmount, remainingTakerAssetAmount));
}
function calculateExpectedOrderInfo(
order: Order,
orderInfo: OrderInfo,
fillResults: FillResults,
): OrderInfo {
const orderTakerAssetFilledAmount =
orderInfo.orderTakerAssetFilledAmount.plus(fillResults.takerAssetFilledAmount);
const orderStatus = orderTakerAssetFilledAmount.gte(order.takerAssetAmount) ?
OrderStatus.FullyFilled : OrderStatus.Fillable;
function calculateExpectedOrderInfo(order: Order, orderInfo: OrderInfo, fillResults: FillResults): OrderInfo {
const orderTakerAssetFilledAmount = orderInfo.orderTakerAssetFilledAmount.plus(
fillResults.takerAssetFilledAmount,
);
const orderStatus = orderTakerAssetFilledAmount.gte(order.takerAssetAmount)
? OrderStatus.FullyFilled
: OrderStatus.Fillable;
return {
orderHash: exchange.getOrderHash(order),
orderStatus,
@ -141,10 +123,7 @@ blockchainTests('Isolated fillOrder() tests', env => {
};
}
function calculateExpectedFillBalances(
order: Order,
fillResults: FillResults,
): AssetBalances {
function calculateExpectedFillBalances(order: Order, fillResults: FillResults): AssetBalances {
const balances: AssetBalances = {};
const addBalance = (assetData: string, address: string, amount: BigNumber) => {
balances[assetData] = balances[assetData] || {};
@ -176,7 +155,7 @@ blockchainTests('Isolated fillOrder() tests', env => {
expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled);
});
it('can\'t overfill an order', async () => {
it("can't overfill an order", async () => {
const order = createOrder();
const { orderInfo } = await fillOrderAndAssertResultsAsync(order, order.takerAssetAmount.times(1.01));
expect(orderInfo.orderStatus).to.eq(OrderStatus.FullyFilled);
@ -266,7 +245,7 @@ blockchainTests('Isolated fillOrder() tests', env => {
expect(orderInfos[1].orderStatus).to.eq(OrderStatus.Fillable);
});
it('can\'t overfill an order in two fills', async () => {
it("can't overfill an order in two fills", async () => {
const order = createOrder();
const fillAmounts = splitAmount(order.takerAssetAmount);
fillAmounts[0] = fillAmounts[0].times(1.01);
@ -320,7 +299,7 @@ blockchainTests('Isolated fillOrder() tests', env => {
});
describe('bad fills', () => {
it('can\'t fill an order with zero takerAssetAmount', async () => {
it("can't fill an order with zero takerAssetAmount", async () => {
const order = createOrder({
takerAssetAmount: ZERO_AMOUNT,
});
@ -328,11 +307,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
exchange.getOrderHash(order),
OrderStatus.InvalidTakerAssetAmount,
);
return expect(exchange.fillOrderAsync(order, ONE_ETHER))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, ONE_ETHER)).to.revertWith(expectedError);
});
it('can\'t fill an order with zero makerAssetAmount', async () => {
it("can't fill an order with zero makerAssetAmount", async () => {
const order = createOrder({
makerAssetAmount: ZERO_AMOUNT,
});
@ -340,22 +318,20 @@ blockchainTests('Isolated fillOrder() tests', env => {
exchange.getOrderHash(order),
OrderStatus.InvalidMakerAssetAmount,
);
return expect(exchange.fillOrderAsync(order, ONE_ETHER))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, ONE_ETHER)).to.revertWith(expectedError);
});
it('can\'t fill an order that is fully filled', async () => {
it("can't fill an order that is fully filled", async () => {
const order = createOrder();
const expectedError = new ExchangeRevertErrors.OrderStatusError(
exchange.getOrderHash(order),
OrderStatus.FullyFilled,
);
await exchange.fillOrderAsync(order, order.takerAssetAmount);
return expect(exchange.fillOrderAsync(order, 1))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, 1)).to.revertWith(expectedError);
});
it('can\'t fill an order that is expired', async () => {
it("can't fill an order that is expired", async () => {
const order = createOrder({
expirationTimeSeconds: new BigNumber(getCurrentTime() - 60),
});
@ -363,11 +339,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
exchange.getOrderHash(order),
OrderStatus.Expired,
);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order that is cancelled by `cancelOrder()`', async () => {
it("can't fill an order that is cancelled by `cancelOrder()`", async () => {
const order = createOrder({
makerAddress: notTakerAddress,
});
@ -376,11 +351,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
OrderStatus.Cancelled,
);
await exchange.cancelOrderAsync(order, { from: notTakerAddress });
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order that is cancelled by `cancelOrdersUpTo()`', async () => {
it("can't fill an order that is cancelled by `cancelOrdersUpTo()`", async () => {
const order = createOrder({
makerAddress: notTakerAddress,
});
@ -389,11 +363,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
OrderStatus.Cancelled,
);
await exchange.cancelOrdersUpToAsync(order.salt, { from: notTakerAddress });
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order if taker is not `takerAddress`', async () => {
it("can't fill an order if taker is not `takerAddress`", async () => {
const order = createOrder({
takerAddress: randomAddress(),
});
@ -401,11 +374,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
exchange.getOrderHash(order),
takerAddress,
);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order if sender is not `senderAddress`', async () => {
it("can't fill an order if sender is not `senderAddress`", async () => {
const order = createOrder({
senderAddress: randomAddress(),
});
@ -413,11 +385,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
exchange.getOrderHash(order),
takerAddress,
);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order with a taker amount that results in a maker asset rounding error', async () => {
it("can't fill an order with a taker amount that results in a maker asset rounding error", async () => {
const order = createOrder({
makerAssetAmount: new BigNumber(100),
takerAssetAmount: ONE_ETHER,
@ -428,11 +399,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
order.takerAssetAmount,
order.makerAssetAmount,
);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order with a taker amount that results in a maker fee rounding error', async () => {
it("can't fill an order with a taker amount that results in a maker fee rounding error", async () => {
const order = createOrder({
makerAssetAmount: ONE_ETHER.times(2),
takerAssetAmount: ONE_ETHER,
@ -444,11 +414,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
order.makerAssetAmount,
order.makerFee,
);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order with a taker amount that results in a taker fee rounding error', async () => {
it("can't fill an order with a taker amount that results in a taker fee rounding error", async () => {
const order = createOrder({
makerAssetAmount: ONE_ETHER.times(2),
takerAssetAmount: ONE_ETHER,
@ -460,11 +429,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
order.takerAssetAmount,
order.takerFee,
);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order that results in a `makerAssetFilledAmount` overflow.', async () => {
it("can't fill an order that results in a `makerAssetFilledAmount` overflow.", async () => {
// All values need to be large to ensure we don't trigger a Rounding.
const order = createOrder({
makerAssetAmount: MAX_UINT256_ROOT.times(2),
@ -476,11 +444,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
takerAssetFillAmount,
order.makerAssetAmount,
);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order that results in a `makerFeePaid` overflow.', async () => {
it("can't fill an order that results in a `makerFeePaid` overflow.", async () => {
// All values need to be large to ensure we don't trigger a Rounding.
const order = createOrder({
makerAssetAmount: MAX_UINT256_ROOT,
@ -498,11 +465,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
makerAssetFilledAmount,
order.makerFee,
);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order that results in a `takerFeePaid` overflow.', async () => {
it("can't fill an order that results in a `takerFeePaid` overflow.", async () => {
// All values need to be large to ensure we don't trigger a Rounding.
const order = createOrder({
makerAssetAmount: MAX_UINT256_ROOT,
@ -515,11 +481,10 @@ blockchainTests('Isolated fillOrder() tests', env => {
takerAssetFillAmount,
order.takerFee,
);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmount)).to.revertWith(expectedError);
});
it('can\'t fill an order with a bad signature', async () => {
it("can't fill an order with a bad signature", async () => {
const order = createOrder();
const signature = createBadSignature();
const expectedError = new ExchangeRevertErrors.SignatureError(
@ -528,11 +493,12 @@ blockchainTests('Isolated fillOrder() tests', env => {
order.makerAddress,
signature,
);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount, signature))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount, signature)).to.revertWith(
expectedError,
);
});
it('can\'t complementary fill an order with a bad signature that is always checked', async () => {
it("can't complementary fill an order with a bad signature that is always checked", async () => {
const order = createOrder();
const takerAssetFillAmounts = splitAmount(order.takerAssetAmount);
const goodSignature = createGoodSignature(SignatureType.Wallet);
@ -544,42 +510,39 @@ blockchainTests('Isolated fillOrder() tests', env => {
badSignature,
);
await exchange.fillOrderAsync(order, takerAssetFillAmounts[0], goodSignature);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmounts[1], badSignature))
.to.revertWith(expectedError);
return expect(exchange.fillOrderAsync(order, takerAssetFillAmounts[1], badSignature)).to.revertWith(
expectedError,
);
});
const TRANSFER_ERROR = 'TRANSFER_FAILED';
it('can\'t fill an order with a maker asset that fails to transfer', async () => {
it("can't fill an order with a maker asset that fails to transfer", async () => {
const order = createOrder({
makerAssetData: createBadAssetData(),
});
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(TRANSFER_ERROR);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR);
});
it('can\'t fill an order with a taker asset that fails to transfer', async () => {
it("can't fill an order with a taker asset that fails to transfer", async () => {
const order = createOrder({
takerAssetData: createBadAssetData(),
});
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(TRANSFER_ERROR);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR);
});
it('can\'t fill an order with a maker fee asset that fails to transfer', async () => {
it("can't fill an order with a maker fee asset that fails to transfer", async () => {
const order = createOrder({
makerFeeAssetData: createBadAssetData(),
});
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(TRANSFER_ERROR);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR);
});
it('can\'t fill an order with a taker fee asset that fails to transfer', async () => {
it("can't fill an order with a taker fee asset that fails to transfer", async () => {
const order = createOrder({
takerFeeAssetData: createBadAssetData(),
});
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount))
.to.revertWith(TRANSFER_ERROR);
return expect(exchange.fillOrderAsync(order, order.takerAssetAmount)).to.revertWith(TRANSFER_ERROR);
});
});

View File

@ -270,17 +270,9 @@ describe('matchOrders', () => {
const numerator = signedOrderLeft.makerAssetAmount;
const denominator = signedOrderLeft.takerAssetAmount;
const target = signedOrderRight.makerAssetAmount;
const _isRoundingErrorCeil = isRoundingErrorCeil(
numerator,
denominator,
target,
);
const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
expect(_isRoundingErrorCeil).to.be.true();
const _isRoundingErrorFloor = isRoundingErrorFloor(
numerator,
denominator,
target,
);
const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
expect(_isRoundingErrorFloor).to.be.false();
// Match signedOrderLeft with signedOrderRight
// Note that the left maker received a slightly better sell price.
@ -336,17 +328,9 @@ describe('matchOrders', () => {
const numerator = signedOrderRight.takerAssetAmount;
const denominator = signedOrderRight.makerAssetAmount;
const target = signedOrderLeft.takerAssetAmount;
const _isRoundingErrorFloor = isRoundingErrorFloor(
numerator,
denominator,
target,
);
const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
expect(_isRoundingErrorFloor).to.be.true();
const _isRoundingErrorCeil = isRoundingErrorCeil(
numerator,
denominator,
target,
);
const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
expect(_isRoundingErrorCeil).to.be.false();
// Match signedOrderLeft isRoundingErrorFloor right maker received a slightly better purchase price.
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
@ -1414,17 +1398,9 @@ describe('matchOrders', () => {
const numerator = signedOrderLeft.makerAssetAmount;
const denominator = signedOrderLeft.takerAssetAmount;
const target = signedOrderRight.makerAssetAmount;
const _isRoundingErrorCeil = isRoundingErrorCeil(
numerator,
denominator,
target,
);
const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
expect(_isRoundingErrorCeil).to.be.true();
const _isRoundingErrorFloor = isRoundingErrorFloor(
numerator,
denominator,
target,
);
const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
expect(_isRoundingErrorFloor).to.be.false();
// Match signedOrderLeft with signedOrderRight
// Note that the left maker received a slightly better sell price.
@ -1480,17 +1456,9 @@ describe('matchOrders', () => {
const numerator = signedOrderRight.makerAssetAmount;
const denominator = signedOrderRight.takerAssetAmount;
const target = signedOrderLeft.makerAssetAmount;
const _isRoundingErrorCeil = isRoundingErrorCeil(
numerator,
denominator,
target,
);
const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
expect(_isRoundingErrorCeil).to.be.false();
const _isRoundingErrorFloor = isRoundingErrorFloor(
numerator,
denominator,
target,
);
const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
expect(_isRoundingErrorFloor).to.be.false();
// Match signedOrderLeft with signedOrderRight
// Note that the right maker received a slightly better purchase price.

View File

@ -1,9 +1,5 @@
import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
import {
constants,
describe,
expect,
} from '@0x/contracts-test-utils';
import { constants, describe, expect } from '@0x/contracts-test-utils';
import { LibMathRevertErrors } from '@0x/order-utils';
import { OrderWithoutDomain as Order } from '@0x/types';
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
@ -33,11 +29,7 @@ describe('Reference functions', () => {
describe('calculateFillResults', () => {
const MAX_UINT256_ROOT = constants.MAX_UINT256_ROOT;
function makeOrder(details?: Partial<Order>): Order {
return _.assign(
{},
EMPTY_ORDER,
details,
);
return _.assign({}, EMPTY_ORDER, details);
}
it('reverts if computing `fillResults.makerAssetFilledAmount` overflows', () => {
@ -52,8 +44,7 @@ describe('Reference functions', () => {
takerAssetFilledAmount,
order.makerAssetAmount,
);
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if computing `fillResults.makerFeePaid` overflows', () => {
@ -74,8 +65,7 @@ describe('Reference functions', () => {
makerAssetFilledAmount,
order.makerFee,
);
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if computing `fillResults.takerFeePaid` overflows', () => {
@ -91,8 +81,7 @@ describe('Reference functions', () => {
takerAssetFilledAmount,
order.takerFee,
);
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if `order.makerAssetAmount` is 0', () => {
@ -102,8 +91,7 @@ describe('Reference functions', () => {
});
const takerAssetFilledAmount = ONE_ETHER;
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if `order.takerAssetAmount` is 0', () => {
@ -113,8 +101,7 @@ describe('Reference functions', () => {
});
const takerAssetFilledAmount = ONE_ETHER;
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', () => {
@ -128,8 +115,7 @@ describe('Reference functions', () => {
order.takerAssetAmount,
order.makerAssetAmount,
);
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if there is a rounding error computing `makerFeePaid`', () => {
@ -149,8 +135,7 @@ describe('Reference functions', () => {
order.makerAssetAmount,
order.makerFee,
);
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
it('reverts if there is a rounding error computing `takerFeePaid`', () => {
@ -170,8 +155,7 @@ describe('Reference functions', () => {
order.makerAssetAmount,
order.takerFee,
);
return expect(() => calculateFillResults(order, takerAssetFilledAmount))
.to.throw(expectedError.message);
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
});
});
});

View File

@ -1,12 +1,7 @@
import { artifacts as erc1155Artifacts } from '@0x/contracts-erc1155';
import { artifacts as erc20Artifacts } from '@0x/contracts-erc20';
import { artifacts as erc721Artifacts } from '@0x/contracts-erc721';
import {
BatchMatchOrder,
LogDecoder,
orderUtils,
Web3ProviderEngine,
} from '@0x/contracts-test-utils';
import { BatchMatchOrder, LogDecoder, orderUtils, Web3ProviderEngine } from '@0x/contracts-test-utils';
import {
BatchMatchedFillResults,
FillResults,

View File

@ -1,5 +1,3 @@
import { BigNumber } from '@0x/utils';
export enum FeeRecipientAddressScenario {
BurnAddress = 'BURN_ADDRESS',
EthUserAddress = 'ETH_USER_ADDRESS',

View File

@ -130,9 +130,7 @@ export class IsolatedExchangeWrapper {
await this.instance.fillOrder.sendTransactionAsync.call(this.instance, ...args),
);
this.lastTxEvents = extractEvents(receipt.logs);
this.lastTxBalanceChanges = getBalanceChangesFromTransferFromCalls(
this.lastTxEvents.transferFromCalls,
);
this.lastTxBalanceChanges = getBalanceChangesFromTransferFromCalls(this.lastTxEvents.transferFromCalls);
return result;
}
}
@ -179,21 +177,16 @@ function createEmptyEvents(): IsolatedExchangeEvents {
function extractEvents(logs: LogEntry[]): IsolatedExchangeEvents {
return {
fillEvents: filterLogsToArguments<FillEventArgs>(logs, 'Fill'),
transferFromCalls: filterLogsToArguments<DispatchTransferFromCallArgs>(
logs,
'DispatchTransferFromCalled',
),
transferFromCalls: filterLogsToArguments<DispatchTransferFromCallArgs>(logs, 'DispatchTransferFromCalled'),
};
}
// Executes transferFrom calls to compute relative balances for addresses.
function getBalanceChangesFromTransferFromCalls(
calls: DispatchTransferFromCallArgs[],
): AssetBalances {
function getBalanceChangesFromTransferFromCalls(calls: DispatchTransferFromCallArgs[]): AssetBalances {
const changes: AssetBalances = {};
for (const call of calls) {
const { assetData, from, to, amount } = call;
const balances = changes[assetData] = changes[assetData ] || {};
const balances = (changes[assetData] = changes[assetData] || {});
const fromBalance = balances[from] || constants.ZERO_AMOUNT;
const toBalance = balances[to] || constants.ZERO_AMOUNT;
balances[from] = fromBalance.minus(amount);

View File

@ -1,17 +1,7 @@
import { ERC1155ProxyWrapper, ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy';
import {
ERC1155HoldingsByOwner,
expect,
OrderStatus,
} from '@0x/contracts-test-utils';
import { ERC1155HoldingsByOwner, expect, OrderStatus } from '@0x/contracts-test-utils';
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
import {
AssetProxyId,
BatchMatchedFillResults,
FillResults,
MatchedFillResults,
SignedOrder,
} from '@0x/types';
import { AssetProxyId, BatchMatchedFillResults, FillResults, MatchedFillResults, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';

View File

@ -2,5 +2,8 @@
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
},
"linterOptions": {
"exclude": ["src/artifacts.ts"]
}
}

View File

@ -61,7 +61,7 @@
{
"note": "Update `testWithReferenceFuncAsync` to work with `RevertErrors`",
"pr": "TODO"
},
}
]
},
{

View File

@ -83,11 +83,7 @@ export async function testWithReferenceFuncAsync(
if (expectedError !== undefined) {
// Expecting an error.
if (actualError === undefined) {
return expect.fail(
actualError,
expectedError,
`${testCaseString}: expected failure but instead succeeded`,
);
return expect.fail(actualError, expectedError, `${testCaseString}: expected failure but instead succeeded`);
} else {
if (expectedError instanceof RevertError) {
// Expecting a RevertError.
@ -112,7 +108,9 @@ export async function testWithReferenceFuncAsync(
return expect.fail(
actualError,
expectedError,
`${testCaseString}: expected error message '${actualError.message}' to equal '${expectedError.message}'`,
`${testCaseString}: expected error message '${actualError.message}' to equal '${
expectedError.message
}'`,
);
}
}
@ -120,11 +118,7 @@ export async function testWithReferenceFuncAsync(
} else {
// Not expecting an error.
if (actualError !== undefined) {
return expect.fail(
actualError,
expectedError,
`${testCaseString}: expected success but instead failed`,
);
return expect.fail(actualError, expectedError, `${testCaseString}: expected success but instead failed`);
}
if (expected instanceof BigNumber) {
// Technically we can do this with `deep.eq`, but this prints prettier

View File

@ -28,8 +28,9 @@ describe('testWithReferenceFuncAsync', () => {
});
it('fails when both succeed and actual != expected', async () => {
return expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2]))
.to.be.rejectedWith('{"x":1,"y":2}: expected 0.5 to deeply equal 3');
return expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2])).to.be.rejectedWith(
'{"x":1,"y":2}: expected 0.5 to deeply equal 3',
);
});
it('passes when both fail and error messages are the same', async () => {
@ -44,9 +45,7 @@ describe('testWithReferenceFuncAsync', () => {
const notError = new Error(notErrorMessage);
return expect(
testWithReferenceFuncAsync(alwaysFailFunc(notError), alwaysFailFunc(error), [1, 2]),
).to.be.rejectedWith(
`{"x":1,"y":2}: expected error message '${errorMessage}' to equal '${notErrorMessage}'`,
);
).to.be.rejectedWith(`{"x":1,"y":2}: expected error message '${errorMessage}' to equal '${notErrorMessage}'`);
});
it('passes when both fail with compatible RevertErrors', async () => {
@ -58,34 +57,32 @@ describe('testWithReferenceFuncAsync', () => {
it('fails when both fail with incompatible RevertErrors', async () => {
const error1 = new StringRevertError('whoopsie');
const error2 = new StringRevertError('not whoopsie');
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1]))
.to.be.rejectedWith(
`{"x":1,"y":1}: expected error StringRevertError({ message: 'not whoopsie' }) to equal StringRevertError({ message: 'whoopsie' })`,
);
return expect(
testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1]),
).to.be.rejectedWith(
`{"x":1,"y":1}: expected error StringRevertError({ message: 'not whoopsie' }) to equal StringRevertError({ message: 'whoopsie' })`,
);
});
it('fails when reference function fails with a RevertError but test function fails with a regular Error', async () => {
const error1 = new StringRevertError('whoopsie');
const error2 = new Error('whoopsie');
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1]))
.to.be.rejectedWith(
`{"x":1,"y":1}: expected a RevertError but received an Error`,
);
return expect(
testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1]),
).to.be.rejectedWith(`{"x":1,"y":1}: expected a RevertError but received an Error`);
});
it('fails when referenceFunc succeeds and testFunc fails', async () => {
const error = new Error('whoopsie');
return expect(testWithReferenceFuncAsync(alwaysValueFunc(0), alwaysFailFunc(error), [1, 2]))
.to.be.rejectedWith(
`{"x":1,"y":2}: expected success but instead failed`,
);
return expect(testWithReferenceFuncAsync(alwaysValueFunc(0), alwaysFailFunc(error), [1, 2])).to.be.rejectedWith(
`{"x":1,"y":2}: expected success but instead failed`,
);
});
it('fails when referenceFunc fails and testFunc succeeds', async () => {
const error = new Error('whoopsie');
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error), divAsync, [1, 2]))
.to.be.rejectedWith(
'{"x":1,"y":2}: expected failure but instead succeeded',
);
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error), divAsync, [1, 2])).to.be.rejectedWith(
'{"x":1,"y":2}: expected failure but instead succeeded',
);
});
});

View File

@ -2,6 +2,9 @@ import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
/**
* Add two `uint256` values. Reverts on overflow.
*/
export function safeAdd(a: BigNumber, b: BigNumber): BigNumber {
const r = a.plus(b);
if (r.isGreaterThan(MAX_UINT256)) {
@ -14,6 +17,9 @@ export function safeAdd(a: BigNumber, b: BigNumber): BigNumber {
return r;
}
/**
* Subract two `uint256` values. Reverts on overflow.
*/
export function safeSub(a: BigNumber, b: BigNumber): BigNumber {
const r = a.minus(b);
if (r.isLessThan(0)) {
@ -26,6 +32,9 @@ export function safeSub(a: BigNumber, b: BigNumber): BigNumber {
return r;
}
/**
* Multiplies two `uint256` values. Reverts on overflow.
*/
export function safeMul(a: BigNumber, b: BigNumber): BigNumber {
const r = a.times(b);
if (r.isGreaterThan(MAX_UINT256)) {
@ -38,6 +47,9 @@ export function safeMul(a: BigNumber, b: BigNumber): BigNumber {
return r;
}
/**
* Divides two `uint256` values. Reverts on division by zero.
*/
export function safeDiv(a: BigNumber, b: BigNumber): BigNumber {
if (b.isEqualTo(0)) {
throw new SafeMathRevertErrors.SafeMathError(