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

View File

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

View File

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

View File

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

View File

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

View File

@ -64,7 +64,7 @@ contract IsolatedExchange is
// Fail if the first byte is 0. // Fail if the first byte is 0.
if (assetData.length > 0 && assetData[0] == 0x00) { 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; const { safeGetPartialAmountFloor } = ExchangeLibsReferenceFunctions;
export function calculateFillResults( /**
order: OrderWithoutDomain, * Calculates amounts filled and fees paid by maker and taker.
takerAssetFilledAmount: BigNumber, */
): FillResults { export function calculateFillResults(order: OrderWithoutDomain, takerAssetFilledAmount: BigNumber): FillResults {
const makerAssetFilledAmount = safeGetPartialAmountFloor( const makerAssetFilledAmount = safeGetPartialAmountFloor(
takerAssetFilledAmount, takerAssetFilledAmount,
order.takerAssetAmount, order.takerAssetAmount,
order.makerAssetAmount, order.makerAssetAmount,
); );
const makerFeePaid = safeGetPartialAmountFloor( const makerFeePaid = safeGetPartialAmountFloor(makerAssetFilledAmount, order.makerAssetAmount, order.makerFee);
makerAssetFilledAmount, const takerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.takerFee);
order.makerAssetAmount,
order.makerFee,
);
const takerFeePaid = safeGetPartialAmountFloor(
takerAssetFilledAmount,
order.takerAssetAmount,
order.takerFee,
);
return { return {
makerAssetFilledAmount, makerAssetFilledAmount,
takerAssetFilledAmount, takerAssetFilledAmount,

View File

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

View File

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

View File

@ -270,17 +270,9 @@ describe('matchOrders', () => {
const numerator = signedOrderLeft.makerAssetAmount; const numerator = signedOrderLeft.makerAssetAmount;
const denominator = signedOrderLeft.takerAssetAmount; const denominator = signedOrderLeft.takerAssetAmount;
const target = signedOrderRight.makerAssetAmount; const target = signedOrderRight.makerAssetAmount;
const _isRoundingErrorCeil = isRoundingErrorCeil( const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorCeil).to.be.true(); expect(_isRoundingErrorCeil).to.be.true();
const _isRoundingErrorFloor = isRoundingErrorFloor( const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorFloor).to.be.false(); expect(_isRoundingErrorFloor).to.be.false();
// Match signedOrderLeft with signedOrderRight // Match signedOrderLeft with signedOrderRight
// Note that the left maker received a slightly better sell price. // Note that the left maker received a slightly better sell price.
@ -336,17 +328,9 @@ describe('matchOrders', () => {
const numerator = signedOrderRight.takerAssetAmount; const numerator = signedOrderRight.takerAssetAmount;
const denominator = signedOrderRight.makerAssetAmount; const denominator = signedOrderRight.makerAssetAmount;
const target = signedOrderLeft.takerAssetAmount; const target = signedOrderLeft.takerAssetAmount;
const _isRoundingErrorFloor = isRoundingErrorFloor( const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorFloor).to.be.true(); expect(_isRoundingErrorFloor).to.be.true();
const _isRoundingErrorCeil = isRoundingErrorCeil( const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorCeil).to.be.false(); expect(_isRoundingErrorCeil).to.be.false();
// Match signedOrderLeft isRoundingErrorFloor right maker received a slightly better purchase price. // Match signedOrderLeft isRoundingErrorFloor right maker received a slightly better purchase price.
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults. // This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
@ -1414,17 +1398,9 @@ describe('matchOrders', () => {
const numerator = signedOrderLeft.makerAssetAmount; const numerator = signedOrderLeft.makerAssetAmount;
const denominator = signedOrderLeft.takerAssetAmount; const denominator = signedOrderLeft.takerAssetAmount;
const target = signedOrderRight.makerAssetAmount; const target = signedOrderRight.makerAssetAmount;
const _isRoundingErrorCeil = isRoundingErrorCeil( const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorCeil).to.be.true(); expect(_isRoundingErrorCeil).to.be.true();
const _isRoundingErrorFloor = isRoundingErrorFloor( const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorFloor).to.be.false(); expect(_isRoundingErrorFloor).to.be.false();
// Match signedOrderLeft with signedOrderRight // Match signedOrderLeft with signedOrderRight
// Note that the left maker received a slightly better sell price. // Note that the left maker received a slightly better sell price.
@ -1480,17 +1456,9 @@ describe('matchOrders', () => {
const numerator = signedOrderRight.makerAssetAmount; const numerator = signedOrderRight.makerAssetAmount;
const denominator = signedOrderRight.takerAssetAmount; const denominator = signedOrderRight.takerAssetAmount;
const target = signedOrderLeft.makerAssetAmount; const target = signedOrderLeft.makerAssetAmount;
const _isRoundingErrorCeil = isRoundingErrorCeil( const _isRoundingErrorCeil = isRoundingErrorCeil(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorCeil).to.be.false(); expect(_isRoundingErrorCeil).to.be.false();
const _isRoundingErrorFloor = isRoundingErrorFloor( const _isRoundingErrorFloor = isRoundingErrorFloor(numerator, denominator, target);
numerator,
denominator,
target,
);
expect(_isRoundingErrorFloor).to.be.false(); expect(_isRoundingErrorFloor).to.be.false();
// Match signedOrderLeft with signedOrderRight // Match signedOrderLeft with signedOrderRight
// Note that the right maker received a slightly better purchase price. // 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 { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
import { import { constants, describe, expect } from '@0x/contracts-test-utils';
constants,
describe,
expect,
} from '@0x/contracts-test-utils';
import { LibMathRevertErrors } from '@0x/order-utils'; import { LibMathRevertErrors } from '@0x/order-utils';
import { OrderWithoutDomain as Order } from '@0x/types'; import { OrderWithoutDomain as Order } from '@0x/types';
import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
@ -33,11 +29,7 @@ describe('Reference functions', () => {
describe('calculateFillResults', () => { describe('calculateFillResults', () => {
const MAX_UINT256_ROOT = constants.MAX_UINT256_ROOT; const MAX_UINT256_ROOT = constants.MAX_UINT256_ROOT;
function makeOrder(details?: Partial<Order>): Order { function makeOrder(details?: Partial<Order>): Order {
return _.assign( return _.assign({}, EMPTY_ORDER, details);
{},
EMPTY_ORDER,
details,
);
} }
it('reverts if computing `fillResults.makerAssetFilledAmount` overflows', () => { it('reverts if computing `fillResults.makerAssetFilledAmount` overflows', () => {
@ -52,8 +44,7 @@ describe('Reference functions', () => {
takerAssetFilledAmount, takerAssetFilledAmount,
order.makerAssetAmount, order.makerAssetAmount,
); );
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if computing `fillResults.makerFeePaid` overflows', () => { it('reverts if computing `fillResults.makerFeePaid` overflows', () => {
@ -74,8 +65,7 @@ describe('Reference functions', () => {
makerAssetFilledAmount, makerAssetFilledAmount,
order.makerFee, order.makerFee,
); );
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if computing `fillResults.takerFeePaid` overflows', () => { it('reverts if computing `fillResults.takerFeePaid` overflows', () => {
@ -91,8 +81,7 @@ describe('Reference functions', () => {
takerAssetFilledAmount, takerAssetFilledAmount,
order.takerFee, order.takerFee,
); );
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if `order.makerAssetAmount` is 0', () => { it('reverts if `order.makerAssetAmount` is 0', () => {
@ -102,8 +91,7 @@ describe('Reference functions', () => {
}); });
const takerAssetFilledAmount = ONE_ETHER; const takerAssetFilledAmount = ONE_ETHER;
const expectedError = new LibMathRevertErrors.DivisionByZeroError(); const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if `order.takerAssetAmount` is 0', () => { it('reverts if `order.takerAssetAmount` is 0', () => {
@ -113,8 +101,7 @@ describe('Reference functions', () => {
}); });
const takerAssetFilledAmount = ONE_ETHER; const takerAssetFilledAmount = ONE_ETHER;
const expectedError = new LibMathRevertErrors.DivisionByZeroError(); const expectedError = new LibMathRevertErrors.DivisionByZeroError();
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', () => { it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', () => {
@ -128,8 +115,7 @@ describe('Reference functions', () => {
order.takerAssetAmount, order.takerAssetAmount,
order.makerAssetAmount, order.makerAssetAmount,
); );
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if there is a rounding error computing `makerFeePaid`', () => { it('reverts if there is a rounding error computing `makerFeePaid`', () => {
@ -149,8 +135,7 @@ describe('Reference functions', () => {
order.makerAssetAmount, order.makerAssetAmount,
order.makerFee, order.makerFee,
); );
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
it('reverts if there is a rounding error computing `takerFeePaid`', () => { it('reverts if there is a rounding error computing `takerFeePaid`', () => {
@ -170,8 +155,7 @@ describe('Reference functions', () => {
order.makerAssetAmount, order.makerAssetAmount,
order.takerFee, order.takerFee,
); );
return expect(() => calculateFillResults(order, takerAssetFilledAmount)) return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
.to.throw(expectedError.message);
}); });
}); });
}); });

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -83,11 +83,7 @@ export async function testWithReferenceFuncAsync(
if (expectedError !== undefined) { if (expectedError !== undefined) {
// Expecting an error. // Expecting an error.
if (actualError === undefined) { if (actualError === undefined) {
return expect.fail( return expect.fail(actualError, expectedError, `${testCaseString}: expected failure but instead succeeded`);
actualError,
expectedError,
`${testCaseString}: expected failure but instead succeeded`,
);
} else { } else {
if (expectedError instanceof RevertError) { if (expectedError instanceof RevertError) {
// Expecting a RevertError. // Expecting a RevertError.
@ -112,7 +108,9 @@ export async function testWithReferenceFuncAsync(
return expect.fail( return expect.fail(
actualError, actualError,
expectedError, 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 { } else {
// Not expecting an error. // Not expecting an error.
if (actualError !== undefined) { if (actualError !== undefined) {
return expect.fail( return expect.fail(actualError, expectedError, `${testCaseString}: expected success but instead failed`);
actualError,
expectedError,
`${testCaseString}: expected success but instead failed`,
);
} }
if (expected instanceof BigNumber) { if (expected instanceof BigNumber) {
// Technically we can do this with `deep.eq`, but this prints prettier // 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 () => { it('fails when both succeed and actual != expected', async () => {
return expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2])) return expect(testWithReferenceFuncAsync(alwaysValueFunc(3), divAsync, [1, 2])).to.be.rejectedWith(
.to.be.rejectedWith('{"x":1,"y":2}: expected 0.5 to deeply equal 3'); '{"x":1,"y":2}: expected 0.5 to deeply equal 3',
);
}); });
it('passes when both fail and error messages are the same', async () => { it('passes when both fail and error messages are the same', async () => {
@ -44,9 +45,7 @@ describe('testWithReferenceFuncAsync', () => {
const notError = new Error(notErrorMessage); const notError = new Error(notErrorMessage);
return expect( return expect(
testWithReferenceFuncAsync(alwaysFailFunc(notError), alwaysFailFunc(error), [1, 2]), testWithReferenceFuncAsync(alwaysFailFunc(notError), alwaysFailFunc(error), [1, 2]),
).to.be.rejectedWith( ).to.be.rejectedWith(`{"x":1,"y":2}: expected error message '${errorMessage}' to equal '${notErrorMessage}'`);
`{"x":1,"y":2}: expected error message '${errorMessage}' to equal '${notErrorMessage}'`,
);
}); });
it('passes when both fail with compatible RevertErrors', async () => { it('passes when both fail with compatible RevertErrors', async () => {
@ -58,34 +57,32 @@ describe('testWithReferenceFuncAsync', () => {
it('fails when both fail with incompatible RevertErrors', async () => { it('fails when both fail with incompatible RevertErrors', async () => {
const error1 = new StringRevertError('whoopsie'); const error1 = new StringRevertError('whoopsie');
const error2 = new StringRevertError('not whoopsie'); const error2 = new StringRevertError('not whoopsie');
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1])) return expect(
.to.be.rejectedWith( testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1]),
`{"x":1,"y":1}: expected error StringRevertError({ message: 'not whoopsie' }) to equal StringRevertError({ message: 'whoopsie' })`, ).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 () => { it('fails when reference function fails with a RevertError but test function fails with a regular Error', async () => {
const error1 = new StringRevertError('whoopsie'); const error1 = new StringRevertError('whoopsie');
const error2 = new Error('whoopsie'); const error2 = new Error('whoopsie');
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1])) return expect(
.to.be.rejectedWith( testWithReferenceFuncAsync(alwaysFailFunc(error1), alwaysFailFunc(error2), [1, 1]),
`{"x":1,"y":1}: expected a RevertError but received an Error`, ).to.be.rejectedWith(`{"x":1,"y":1}: expected a RevertError but received an Error`);
);
}); });
it('fails when referenceFunc succeeds and testFunc fails', async () => { it('fails when referenceFunc succeeds and testFunc fails', async () => {
const error = new Error('whoopsie'); const error = new Error('whoopsie');
return expect(testWithReferenceFuncAsync(alwaysValueFunc(0), alwaysFailFunc(error), [1, 2])) return expect(testWithReferenceFuncAsync(alwaysValueFunc(0), alwaysFailFunc(error), [1, 2])).to.be.rejectedWith(
.to.be.rejectedWith( `{"x":1,"y":2}: expected success but instead failed`,
`{"x":1,"y":2}: expected success but instead failed`, );
);
}); });
it('fails when referenceFunc fails and testFunc succeeds', async () => { it('fails when referenceFunc fails and testFunc succeeds', async () => {
const error = new Error('whoopsie'); const error = new Error('whoopsie');
return expect(testWithReferenceFuncAsync(alwaysFailFunc(error), divAsync, [1, 2])) return expect(testWithReferenceFuncAsync(alwaysFailFunc(error), divAsync, [1, 2])).to.be.rejectedWith(
.to.be.rejectedWith( '{"x":1,"y":2}: expected failure but instead succeeded',
'{"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); 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 { export function safeAdd(a: BigNumber, b: BigNumber): BigNumber {
const r = a.plus(b); const r = a.plus(b);
if (r.isGreaterThan(MAX_UINT256)) { if (r.isGreaterThan(MAX_UINT256)) {
@ -14,6 +17,9 @@ export function safeAdd(a: BigNumber, b: BigNumber): BigNumber {
return r; return r;
} }
/**
* Subract two `uint256` values. Reverts on overflow.
*/
export function safeSub(a: BigNumber, b: BigNumber): BigNumber { export function safeSub(a: BigNumber, b: BigNumber): BigNumber {
const r = a.minus(b); const r = a.minus(b);
if (r.isLessThan(0)) { if (r.isLessThan(0)) {
@ -26,6 +32,9 @@ export function safeSub(a: BigNumber, b: BigNumber): BigNumber {
return r; return r;
} }
/**
* Multiplies two `uint256` values. Reverts on overflow.
*/
export function safeMul(a: BigNumber, b: BigNumber): BigNumber { export function safeMul(a: BigNumber, b: BigNumber): BigNumber {
const r = a.times(b); const r = a.times(b);
if (r.isGreaterThan(MAX_UINT256)) { if (r.isGreaterThan(MAX_UINT256)) {
@ -38,6 +47,9 @@ export function safeMul(a: BigNumber, b: BigNumber): BigNumber {
return r; return r;
} }
/**
* Divides two `uint256` values. Reverts on division by zero.
*/
export function safeDiv(a: BigNumber, b: BigNumber): BigNumber { export function safeDiv(a: BigNumber, b: BigNumber): BigNumber {
if (b.isEqualTo(0)) { if (b.isEqualTo(0)) {
throw new SafeMathRevertErrors.SafeMathError( throw new SafeMathRevertErrors.SafeMathError(