@0x/contracts-exchange-libs
: Add explicit tests for LibMath
and LibFillResults
functions.
`@0x/contracts-exchange-libs`: Add tests for `ReferenceFunctions`.
This commit is contained in:
parent
a179a6892c
commit
293510c087
@ -1,16 +1,17 @@
|
|||||||
import {
|
import {
|
||||||
blockchainTests,
|
blockchainTests,
|
||||||
|
constants,
|
||||||
describe,
|
describe,
|
||||||
testCombinatoriallyWithReferenceFunc,
|
expect,
|
||||||
uint256Values,
|
|
||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { FillResults } from '@0x/types';
|
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { artifacts, ReferenceFunctions, TestLibsContract } from '../src';
|
import { artifacts, ReferenceFunctions, TestLibsContract } from '../src';
|
||||||
|
|
||||||
blockchainTests('LibFillResults', env => {
|
blockchainTests('LibFillResults', env => {
|
||||||
const CHAIN_ID = 1337;
|
const CHAIN_ID = 1337;
|
||||||
|
const { ONE_ETHER, MAX_UINT256 } = constants;
|
||||||
let libsContract: TestLibsContract;
|
let libsContract: TestLibsContract;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -23,47 +24,76 @@ blockchainTests('LibFillResults', env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('addFillResults', () => {
|
describe('addFillResults', () => {
|
||||||
function makeFillResults(value: BigNumber): FillResults {
|
describe('explicit tests', () => {
|
||||||
// HACK(dorothy-zbornak): We reuse values across fields,
|
const DEFAULT_FILL_RESULTS = [
|
||||||
// but this is fine because `addFillResults()` never does
|
{
|
||||||
// any math between them.
|
makerAssetFilledAmount: ONE_ETHER,
|
||||||
return {
|
takerAssetFilledAmount: ONE_ETHER.times(2),
|
||||||
makerAssetFilledAmount: value,
|
makerFeePaid: ONE_ETHER.times(0.001),
|
||||||
takerAssetFilledAmount: value,
|
takerFeePaid: ONE_ETHER.times(0.002),
|
||||||
makerFeePaid: value,
|
},
|
||||||
takerFeePaid: value,
|
{
|
||||||
};
|
makerAssetFilledAmount: ONE_ETHER.times(0.01),
|
||||||
}
|
takerAssetFilledAmount: ONE_ETHER.times(2).times(0.01),
|
||||||
|
makerFeePaid: ONE_ETHER.times(0.001).times(0.01),
|
||||||
|
takerFeePaid: ONE_ETHER.times(0.002).times(0.01),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
async function referenceAddFillResultsAsync(
|
it('matches the output of the reference function', async () => {
|
||||||
totalValue: BigNumber,
|
const [ a, b ] = DEFAULT_FILL_RESULTS;
|
||||||
singleValue: BigNumber,
|
const expected = ReferenceFunctions.addFillResults(a, b);
|
||||||
): Promise<FillResults> {
|
const actual = await libsContract.addFillResults.callAsync(a, b);
|
||||||
return ReferenceFunctions.addFillResults(
|
expect(actual).to.deep.equal(expected);
|
||||||
makeFillResults(totalValue),
|
});
|
||||||
makeFillResults(singleValue),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function testAddFillResultsAsync(
|
it('reverts if computing `makerAssetFilledAmount` overflows', async () => {
|
||||||
totalValue: BigNumber,
|
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||||
singleValue: BigNumber,
|
b.makerAssetFilledAmount = MAX_UINT256;
|
||||||
): Promise<FillResults> {
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
return libsContract.addFillResults.callAsync(
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||||
makeFillResults(totalValue),
|
a.makerAssetFilledAmount,
|
||||||
makeFillResults(singleValue),
|
b.makerAssetFilledAmount,
|
||||||
);
|
);
|
||||||
}
|
return expect(libsContract.addFillResults.callAsync(a, b))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO(dorothy-zbornak): Do we really need these?
|
it('reverts if computing `takerAssetFilledAmount` overflows', async () => {
|
||||||
// Just a couple edge cases would likely suffice.
|
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||||
describe.optional('combinatorial tests', () => {
|
b.takerAssetFilledAmount = MAX_UINT256;
|
||||||
testCombinatoriallyWithReferenceFunc(
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
'addFillResults',
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||||
referenceAddFillResultsAsync,
|
a.takerAssetFilledAmount,
|
||||||
testAddFillResultsAsync,
|
b.takerAssetFilledAmount,
|
||||||
[uint256Values, uint256Values],
|
);
|
||||||
);
|
return expect(libsContract.addFillResults.callAsync(a, b))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if computing `makerFeePaid` overflows', async () => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if computing `takerFeePaid` overflows', async () => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
blockchainTests,
|
blockchainTests,
|
||||||
|
constants,
|
||||||
describe,
|
describe,
|
||||||
|
expect,
|
||||||
testCombinatoriallyWithReferenceFunc,
|
testCombinatoriallyWithReferenceFunc,
|
||||||
uint256Values,
|
uint256Values,
|
||||||
} from '@0x/contracts-test-utils';
|
} from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { LibMathRevertErrors } from '@0x/order-utils';
|
||||||
|
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||||
|
|
||||||
import { artifacts, ReferenceFunctions, TestLibsContract } from '../src';
|
import { artifacts, ReferenceFunctions, TestLibsContract } from '../src';
|
||||||
|
|
||||||
blockchainTests('LibMath', env => {
|
blockchainTests('LibMath', env => {
|
||||||
const CHAIN_ID = 1337;
|
const CHAIN_ID = 1337;
|
||||||
|
const { ONE_ETHER, MAX_UINT256, MAX_UINT256_ROOT, ZERO_AMOUNT } = constants;
|
||||||
let libsContract: TestLibsContract;
|
let libsContract: TestLibsContract;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -48,6 +52,43 @@ blockchainTests('LibMath', env => {
|
|||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('matches the reference function output', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expected = ReferenceFunctions.getPartialAmountFloor(numerator, denominator, target);
|
||||||
|
const actual = await libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.bignumber.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ZERO_AMOUNT;
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||||
|
numerator.times(target),
|
||||||
|
denominator,
|
||||||
|
);
|
||||||
|
return expect(libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', async () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(libsContract.getPartialAmountFloor.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getPartialAmountCeil', () => {
|
describe('getPartialAmountCeil', () => {
|
||||||
@ -59,6 +100,44 @@ blockchainTests('LibMath', env => {
|
|||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('matches the reference function output', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expected = ReferenceFunctions.getPartialAmountCeil(numerator, denominator, target);
|
||||||
|
const actual = await libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.bignumber.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ZERO_AMOUNT;
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
// This will actually manifest as a subtraction underflow.
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||||
|
denominator,
|
||||||
|
new BigNumber(1),
|
||||||
|
);
|
||||||
|
return expect(libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', async () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(libsContract.getPartialAmountCeil.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('safeGetPartialAmountFloor', () => {
|
describe('safeGetPartialAmountFloor', () => {
|
||||||
@ -70,6 +149,52 @@ blockchainTests('LibMath', env => {
|
|||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('matches the reference function output', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expected = ReferenceFunctions.safeGetPartialAmountFloor(numerator, denominator, target);
|
||||||
|
const actual = await libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.bignumber.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts for a rounding error', async () => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', async () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(libsContract.safeGetPartialAmountFloor.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('safeGetPartialAmountCeil', () => {
|
describe('safeGetPartialAmountCeil', () => {
|
||||||
@ -81,6 +206,52 @@ blockchainTests('LibMath', env => {
|
|||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('matches the reference function output', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expected = ReferenceFunctions.safeGetPartialAmountCeil(numerator, denominator, target);
|
||||||
|
const actual = await libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.bignumber.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts for a rounding error', async () => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', async () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(libsContract.safeGetPartialAmountCeil.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isRoundingErrorFloor', () => {
|
describe('isRoundingErrorFloor', () => {
|
||||||
@ -92,6 +263,55 @@ blockchainTests('LibMath', env => {
|
|||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('returns true for a rounding error', async () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(333);
|
||||||
|
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for not a rounding error', async () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(5e2);
|
||||||
|
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('matches the reference function output', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expected = ReferenceFunctions.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
|
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', async () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isRoundingErrorCeil', () => {
|
describe('isRoundingErrorCeil', () => {
|
||||||
@ -103,5 +323,54 @@ blockchainTests('LibMath', env => {
|
|||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('returns true for a rounding error', async () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(333);
|
||||||
|
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for not a rounding error', async () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(5e2);
|
||||||
|
const actual = await libsContract.isRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('matches the reference function output', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expected = ReferenceFunctions.isRoundingErrorCeil(numerator, denominator, target);
|
||||||
|
const actual = await libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', async () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', async () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(libsContract.isRoundingErrorCeil.callAsync(numerator, denominator, target))
|
||||||
|
.to.revertWith(expectedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
310
contracts/exchange-libs/test/reference_functions.ts
Normal file
310
contracts/exchange-libs/test/reference_functions.ts
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
import {
|
||||||
|
addFillResults,
|
||||||
|
getPartialAmountCeil,
|
||||||
|
getPartialAmountFloor,
|
||||||
|
isRoundingErrorCeil,
|
||||||
|
isRoundingErrorFloor,
|
||||||
|
safeGetPartialAmountCeil,
|
||||||
|
safeGetPartialAmountFloor,
|
||||||
|
} from '../src/reference_functions';
|
||||||
|
|
||||||
|
describe('Reference Functions', () => {
|
||||||
|
const { ONE_ETHER, MAX_UINT256, MAX_UINT256_ROOT, ZERO_AMOUNT } = constants;
|
||||||
|
describe('LibFillResults', () => {
|
||||||
|
|
||||||
|
describe('addFillResults', () => {
|
||||||
|
const DEFAULT_FILL_RESULTS = [
|
||||||
|
{
|
||||||
|
makerAssetFilledAmount: ONE_ETHER,
|
||||||
|
takerAssetFilledAmount: ONE_ETHER.times(2),
|
||||||
|
makerFeePaid: ONE_ETHER.times(0.001),
|
||||||
|
takerFeePaid: ONE_ETHER.times(0.002),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerAssetFilledAmount: ONE_ETHER.times(0.01),
|
||||||
|
takerAssetFilledAmount: ONE_ETHER.times(2).times(0.01),
|
||||||
|
makerFeePaid: ONE_ETHER.times(0.001).times(0.01),
|
||||||
|
takerFeePaid: ONE_ETHER.times(0.002).times(0.01),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
it('reverts if computing `makerAssetFilledAmount` overflows', () => {
|
||||||
|
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||||
|
b.makerAssetFilledAmount = MAX_UINT256;
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||||
|
a.makerAssetFilledAmount,
|
||||||
|
b.makerAssetFilledAmount,
|
||||||
|
);
|
||||||
|
expect(() => addFillResults(a, b)).to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if computing `takerAssetFilledAmount` overflows', () => {
|
||||||
|
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||||
|
b.takerAssetFilledAmount = MAX_UINT256;
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||||
|
a.takerAssetFilledAmount,
|
||||||
|
b.takerAssetFilledAmount,
|
||||||
|
);
|
||||||
|
expect(() => addFillResults(a, b)).to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if computing `makerFeePaid` overflows', () => {
|
||||||
|
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||||
|
b.makerFeePaid = MAX_UINT256;
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||||
|
a.makerFeePaid,
|
||||||
|
b.makerFeePaid,
|
||||||
|
);
|
||||||
|
expect(() => addFillResults(a, b)).to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if computing `takerFeePaid` overflows', () => {
|
||||||
|
const [ a, b ] = _.cloneDeep(DEFAULT_FILL_RESULTS);
|
||||||
|
b.takerFeePaid = MAX_UINT256;
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||||
|
a.takerFeePaid,
|
||||||
|
b.takerFeePaid,
|
||||||
|
);
|
||||||
|
expect(() => addFillResults(a, b)).to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('LibMath', () => {
|
||||||
|
describe('getPartialAmountFloor', () => {
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('reverts if `denominator` is zero', () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ZERO_AMOUNT;
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero,
|
||||||
|
numerator.times(target),
|
||||||
|
denominator,
|
||||||
|
);
|
||||||
|
return expect(() => getPartialAmountFloor(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(() => getPartialAmountFloor(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getPartialAmountCeil', () => {
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('reverts if `denominator` is zero', () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
const denominator = ZERO_AMOUNT;
|
||||||
|
const target = ONE_ETHER.times(0.01);
|
||||||
|
// This will actually manifest as a subtraction underflow.
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256SubtractionUnderflow,
|
||||||
|
denominator,
|
||||||
|
new BigNumber(1),
|
||||||
|
);
|
||||||
|
return expect(() => getPartialAmountCeil(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(() => getPartialAmountCeil(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('safeGetPartialAmountFloor', () => {
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('reverts for a rounding error', () => {
|
||||||
|
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(() => safeGetPartialAmountFloor(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(() => safeGetPartialAmountFloor(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('safeGetPartialAmountCeil', () => {
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('reverts for a rounding error', () => {
|
||||||
|
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(() => safeGetPartialAmountCeil(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(() => safeGetPartialAmountCeil(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isRoundingErrorFloor', () => {
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('returns true for a rounding error', () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(333);
|
||||||
|
const actual = isRoundingErrorFloor(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for not a rounding error', () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(5e2);
|
||||||
|
const actual = isRoundingErrorFloor(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(() => isRoundingErrorFloor(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isRoundingErrorCeil', () => {
|
||||||
|
describe('explicit tests', () => {
|
||||||
|
it('returns true for a rounding error', () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(333);
|
||||||
|
const actual = isRoundingErrorFloor(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for not a rounding error', () => {
|
||||||
|
const numerator = new BigNumber(1e3);
|
||||||
|
const denominator = new BigNumber(1e4);
|
||||||
|
const target = new BigNumber(5e2);
|
||||||
|
const actual = isRoundingErrorFloor(numerator, denominator, target);
|
||||||
|
expect(actual).to.eq(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `denominator` is zero', () => {
|
||||||
|
const numerator = ONE_ETHER;
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reverts if `numerator * target` overflows', () => {
|
||||||
|
const numerator = MAX_UINT256;
|
||||||
|
const denominator = ONE_ETHER.dividedToIntegerBy(2);
|
||||||
|
const target = MAX_UINT256_ROOT.times(2);
|
||||||
|
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||||
|
SafeMathRevertErrors.SafeMathErrorCodes.Uint256MultiplicationOverflow,
|
||||||
|
numerator,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
return expect(() => isRoundingErrorCeil(numerator, denominator, target))
|
||||||
|
.to.throw(expectedError.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user