Add tests
This commit is contained in:
@@ -96,7 +96,7 @@ contract TestExchangeInternals is
|
||||
return getPartialAmountCeil(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error > 0.1%.
|
||||
/// @dev Checks if rounding error >= 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
@@ -112,6 +112,23 @@ contract TestExchangeInternals is
|
||||
{
|
||||
return isRoundingError(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function publicIsRoundingErrorCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
return isRoundingErrorCeil(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
|
||||
@@ -66,6 +66,23 @@ contract TestLibs is
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
function publicGetPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
partialAmount = getPartialAmountCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
);
|
||||
return partialAmount;
|
||||
}
|
||||
|
||||
function publicIsRoundingError(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
@@ -83,6 +100,23 @@ contract TestLibs is
|
||||
return isError;
|
||||
}
|
||||
|
||||
function publicIsRoundingErrorCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
isError = isRoundingErrorCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target
|
||||
);
|
||||
return isError;
|
||||
}
|
||||
|
||||
function publicGetOrderHash(Order memory order)
|
||||
public
|
||||
view
|
||||
|
||||
@@ -294,6 +294,49 @@ describe('Exchange core internal functions', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('isRoundingErrorCeil', async () => {
|
||||
async function referenceIsRoundingErrorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
if (numerator.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
if (target.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
const product = numerator.mul(target);
|
||||
const remainder = product.mod(denominator);
|
||||
const error = denominator.sub(remainder).mod(denominator);
|
||||
const errorTimes1000 = error.mul('1000');
|
||||
const isError = errorTimes1000.gt(product);
|
||||
if (product.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
if (errorTimes1000.greaterThan(MAX_UINT256)) {
|
||||
throw overflowErrorForCall;
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
async function testIsRoundingErrorCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
return testExchange.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingErrorCeil',
|
||||
referenceIsRoundingErrorAsync,
|
||||
testIsRoundingErrorCeilAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('updateFilledState', async () => {
|
||||
// Note(albrow): Since updateFilledState modifies the state by calling
|
||||
// sendTransaction, we must reset the state after each test.
|
||||
|
||||
@@ -71,29 +71,57 @@ describe('Exchange libs', () => {
|
||||
// combinatorial tests in test/exchange/internal. They test specific edge
|
||||
// cases that are not covered by the combinatorial tests.
|
||||
describe('LibMath', () => {
|
||||
it('should return true if there is a rounding error of 0.1%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(999);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
describe('isRoundingError', () => {
|
||||
it('should return true if there is a rounding error of 0.1%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(999);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
it('should return false if there is a rounding of 0.09%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9991);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9989);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
});
|
||||
it('should return false if there is a rounding of 0.09%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9991);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(9989);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
describe('isRoundingErrorCeil', () => {
|
||||
it('should return true if there is a rounding error of 0.1%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(1001);
|
||||
const target = new BigNumber(50);
|
||||
// rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1%
|
||||
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
it('should return false if there is a rounding of 0.09%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(10009);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09%
|
||||
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.false();
|
||||
});
|
||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||
const numerator = new BigNumber(20);
|
||||
const denominator = new BigNumber(10011);
|
||||
const target = new BigNumber(500);
|
||||
// rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11%
|
||||
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
expect(isRoundingError).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user