@0x/contracts-exchange-libs
: Remove unecessary checks for zero
denominator. `@0x/contracts-exchange-libs`: `LibMath` tests from `@0x/contracts-exchange` into this package. `@0x/contracts-exchange-libs`: Adjust logic in reference functions to be closer to solidity implementation.
This commit is contained in:
parent
4600a656d1
commit
f791cd3a37
@ -57,6 +57,14 @@
|
|||||||
{
|
{
|
||||||
"note": "Add reference functions for `LibMath` and `LibFillResults`",
|
"note": "Add reference functions for `LibMath` and `LibFillResults`",
|
||||||
"pr": "TODO"
|
"pr": "TODO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Bring in revamped `LibMath` tests from the `contracts-exchange` package.",
|
||||||
|
"pr": "TODO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Remove unecessary zero-denominator checks in `LibMath`.",
|
||||||
|
"pr": "TODO"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -41,10 +41,6 @@ contract LibMath is
|
|||||||
pure
|
pure
|
||||||
returns (uint256 partialAmount)
|
returns (uint256 partialAmount)
|
||||||
{
|
{
|
||||||
if (denominator == 0) {
|
|
||||||
LibRichErrors._rrevert(LibMathRichErrors.DivisionByZeroError());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_isRoundingErrorFloor(
|
if (_isRoundingErrorFloor(
|
||||||
numerator,
|
numerator,
|
||||||
denominator,
|
denominator,
|
||||||
@ -79,10 +75,6 @@ contract LibMath is
|
|||||||
pure
|
pure
|
||||||
returns (uint256 partialAmount)
|
returns (uint256 partialAmount)
|
||||||
{
|
{
|
||||||
if (denominator == 0) {
|
|
||||||
LibRichErrors._rrevert(LibMathRichErrors.DivisionByZeroError());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_isRoundingErrorCeil(
|
if (_isRoundingErrorCeil(
|
||||||
numerator,
|
numerator,
|
||||||
denominator,
|
denominator,
|
||||||
@ -122,10 +114,6 @@ contract LibMath is
|
|||||||
pure
|
pure
|
||||||
returns (uint256 partialAmount)
|
returns (uint256 partialAmount)
|
||||||
{
|
{
|
||||||
if (denominator == 0) {
|
|
||||||
LibRichErrors._rrevert(LibMathRichErrors.DivisionByZeroError());
|
|
||||||
}
|
|
||||||
|
|
||||||
partialAmount = _safeDiv(
|
partialAmount = _safeDiv(
|
||||||
_safeMul(numerator, target),
|
_safeMul(numerator, target),
|
||||||
denominator
|
denominator
|
||||||
@ -147,10 +135,6 @@ contract LibMath is
|
|||||||
pure
|
pure
|
||||||
returns (uint256 partialAmount)
|
returns (uint256 partialAmount)
|
||||||
{
|
{
|
||||||
if (denominator == 0) {
|
|
||||||
LibRichErrors._rrevert(LibMathRichErrors.DivisionByZeroError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// _safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
|
// _safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
|
||||||
// ceil(a / b) = floor((a + b - 1) / b)
|
// ceil(a / b) = floor((a + b - 1) / b)
|
||||||
// To implement `ceil(a / b)` using _safeDiv.
|
// To implement `ceil(a / b)` using _safeDiv.
|
||||||
|
@ -73,6 +73,40 @@ contract TestLibs is
|
|||||||
return partialAmount;
|
return partialAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function safeGetPartialAmountFloor(
|
||||||
|
uint256 numerator,
|
||||||
|
uint256 denominator,
|
||||||
|
uint256 target
|
||||||
|
)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (uint256 partialAmount)
|
||||||
|
{
|
||||||
|
partialAmount = _safeGetPartialAmountFloor(
|
||||||
|
numerator,
|
||||||
|
denominator,
|
||||||
|
target
|
||||||
|
);
|
||||||
|
return partialAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeGetPartialAmountCeil(
|
||||||
|
uint256 numerator,
|
||||||
|
uint256 denominator,
|
||||||
|
uint256 target
|
||||||
|
)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (uint256 partialAmount)
|
||||||
|
{
|
||||||
|
partialAmount = _safeGetPartialAmountCeil(
|
||||||
|
numerator,
|
||||||
|
denominator,
|
||||||
|
target
|
||||||
|
);
|
||||||
|
return partialAmount;
|
||||||
|
}
|
||||||
|
|
||||||
function isRoundingErrorFloor(
|
function isRoundingErrorFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
|
@ -21,8 +21,11 @@ export function isRoundingErrorFloor(
|
|||||||
if (numerator.eq(0) || target.eq(0)) {
|
if (numerator.eq(0) || target.eq(0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const remainder = numerator.multipliedBy(target).mod(denominator);
|
const remainder = numerator.times(target).mod(denominator);
|
||||||
return safeMul(new BigNumber(1000), remainder).gte(safeMul(numerator, target));
|
// Need to do this separately because solidity evaluates RHS of the comparison expression first.
|
||||||
|
const rhs = safeMul(numerator, target);
|
||||||
|
const lhs = safeMul(new BigNumber(1000), remainder);
|
||||||
|
return lhs.gte(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRoundingErrorCeil(
|
export function isRoundingErrorCeil(
|
||||||
@ -36,9 +39,12 @@ export function isRoundingErrorCeil(
|
|||||||
if (numerator.eq(0) || target.eq(0)) {
|
if (numerator.eq(0) || target.eq(0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let remainder = numerator.multipliedBy(target).mod(denominator);
|
let remainder = numerator.times(target).mod(denominator);
|
||||||
remainder = safeSub(denominator, remainder).mod(denominator);
|
remainder = safeSub(denominator, remainder).mod(denominator);
|
||||||
return safeMul(new BigNumber(1000), remainder).gte(safeMul(numerator, target));
|
// Need to do this separately because solidity evaluates RHS of the comparison expression first.
|
||||||
|
const rhs = safeMul(numerator, target);
|
||||||
|
const lhs = safeMul(new BigNumber(1000), remainder);
|
||||||
|
return lhs.gte(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function safeGetPartialAmountFloor(
|
export function safeGetPartialAmountFloor(
|
||||||
@ -46,9 +52,6 @@ export function safeGetPartialAmountFloor(
|
|||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
): BigNumber {
|
): BigNumber {
|
||||||
if (denominator.eq(0)) {
|
|
||||||
throw new LibMathRevertErrors.DivisionByZeroError();
|
|
||||||
}
|
|
||||||
if (isRoundingErrorFloor(numerator, denominator, target)) {
|
if (isRoundingErrorFloor(numerator, denominator, target)) {
|
||||||
throw new LibMathRevertErrors.RoundingError(numerator, denominator, target);
|
throw new LibMathRevertErrors.RoundingError(numerator, denominator, target);
|
||||||
}
|
}
|
||||||
@ -63,9 +66,6 @@ export function safeGetPartialAmountCeil(
|
|||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
): BigNumber {
|
): BigNumber {
|
||||||
if (denominator.eq(0)) {
|
|
||||||
throw new LibMathRevertErrors.DivisionByZeroError();
|
|
||||||
}
|
|
||||||
if (isRoundingErrorCeil(numerator, denominator, target)) {
|
if (isRoundingErrorCeil(numerator, denominator, target)) {
|
||||||
throw new LibMathRevertErrors.RoundingError(numerator, denominator, target);
|
throw new LibMathRevertErrors.RoundingError(numerator, denominator, target);
|
||||||
}
|
}
|
||||||
@ -83,9 +83,6 @@ export function getPartialAmountFloor(
|
|||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
): BigNumber {
|
): BigNumber {
|
||||||
if (denominator.eq(0)) {
|
|
||||||
throw new LibMathRevertErrors.DivisionByZeroError();
|
|
||||||
}
|
|
||||||
return safeDiv(
|
return safeDiv(
|
||||||
safeMul(numerator, target),
|
safeMul(numerator, target),
|
||||||
denominator,
|
denominator,
|
||||||
@ -97,9 +94,6 @@ export function getPartialAmountCeil(
|
|||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
): BigNumber {
|
): BigNumber {
|
||||||
if (denominator.eq(0)) {
|
|
||||||
throw new LibMathRevertErrors.DivisionByZeroError();
|
|
||||||
}
|
|
||||||
return safeDiv(
|
return safeDiv(
|
||||||
safeAdd(
|
safeAdd(
|
||||||
safeMul(numerator, target),
|
safeMul(numerator, target),
|
||||||
|
109
contracts/exchange-libs/test/lib_math.ts
Normal file
109
contracts/exchange-libs/test/lib_math.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import {
|
||||||
|
blockchainTests,
|
||||||
|
describe,
|
||||||
|
testCombinatoriallyWithReferenceFunc,
|
||||||
|
uint256Values,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { artifacts, ReferenceFunctions, TestLibsContract } from '../src';
|
||||||
|
|
||||||
|
const CHAIN_ID = 1337;
|
||||||
|
|
||||||
|
blockchainTests('LibMath', env => {
|
||||||
|
let libsContract: TestLibsContract;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
libsContract = await TestLibsContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestLibs,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
new BigNumber(CHAIN_ID),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wrap a reference function with identical arguments in a promise.
|
||||||
|
function createAsyncReferenceFunction<T>(
|
||||||
|
ref: (...args: any[]) => T,
|
||||||
|
): (...args: any[]) => Promise<T> {
|
||||||
|
return async (...args: any[]): Promise<T> => {
|
||||||
|
return ref(...args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createContractTestFunction<T>(
|
||||||
|
name: string,
|
||||||
|
): (...args: any[]) => Promise<T> {
|
||||||
|
return async (...args: any[]): Promise<T> => {
|
||||||
|
const method = (libsContract as any)[name] as { callAsync: (...args: any[]) => Promise<T> };
|
||||||
|
return method.callAsync(...args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getPartialAmountFloor', () => {
|
||||||
|
describe.optional('combinatorial tests', () => {
|
||||||
|
testCombinatoriallyWithReferenceFunc(
|
||||||
|
'getPartialAmountFloor',
|
||||||
|
createAsyncReferenceFunction(ReferenceFunctions.getPartialAmountFloor),
|
||||||
|
createContractTestFunction('getPartialAmountFloor'),
|
||||||
|
[uint256Values, uint256Values, uint256Values],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getPartialAmountCeil', () => {
|
||||||
|
describe.optional('combinatorial tests', () => {
|
||||||
|
testCombinatoriallyWithReferenceFunc(
|
||||||
|
'getPartialAmountCeil',
|
||||||
|
createAsyncReferenceFunction(ReferenceFunctions.getPartialAmountCeil),
|
||||||
|
createContractTestFunction('getPartialAmountCeil'),
|
||||||
|
[uint256Values, uint256Values, uint256Values],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('safeGetPartialAmountFloor', () => {
|
||||||
|
describe.optional('combinatorial tests', () => {
|
||||||
|
testCombinatoriallyWithReferenceFunc(
|
||||||
|
'safeGetPartialAmountFloor',
|
||||||
|
createAsyncReferenceFunction(ReferenceFunctions.safeGetPartialAmountFloor),
|
||||||
|
createContractTestFunction('safeGetPartialAmountFloor'),
|
||||||
|
[uint256Values, uint256Values, uint256Values],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('safeGetPartialAmountCeil', () => {
|
||||||
|
describe.optional('combinatorial tests', () => {
|
||||||
|
testCombinatoriallyWithReferenceFunc(
|
||||||
|
'safeGetPartialAmountCeil',
|
||||||
|
createAsyncReferenceFunction(ReferenceFunctions.safeGetPartialAmountCeil),
|
||||||
|
createContractTestFunction('safeGetPartialAmountCeil'),
|
||||||
|
[uint256Values, uint256Values, uint256Values],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isRoundingErrorFloor', () => {
|
||||||
|
describe.optional('combinatorial tests', () => {
|
||||||
|
testCombinatoriallyWithReferenceFunc(
|
||||||
|
'isRoundingErrorFloor',
|
||||||
|
createAsyncReferenceFunction(ReferenceFunctions.isRoundingErrorFloor),
|
||||||
|
createContractTestFunction('isRoundingErrorFloor'),
|
||||||
|
[uint256Values, uint256Values, uint256Values],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isRoundingErrorCeil', () => {
|
||||||
|
describe.optional('combinatorial tests', () => {
|
||||||
|
testCombinatoriallyWithReferenceFunc(
|
||||||
|
'isRoundingErrorCeil',
|
||||||
|
createAsyncReferenceFunction(ReferenceFunctions.isRoundingErrorCeil),
|
||||||
|
createContractTestFunction('isRoundingErrorCeil'),
|
||||||
|
[uint256Values, uint256Values, uint256Values],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user