Append -Floor to getPartialAmount and isRoundingError
This commit is contained in:
@@ -163,7 +163,7 @@ contract MixinExchangeWrapper is
|
|||||||
|
|
||||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
|
||||||
orders[i].takerAssetAmount,
|
orders[i].takerAssetAmount,
|
||||||
orders[i].makerAssetAmount,
|
orders[i].makerAssetAmount,
|
||||||
remainingMakerAssetFillAmount
|
remainingMakerAssetFillAmount
|
||||||
@@ -231,7 +231,7 @@ contract MixinExchangeWrapper is
|
|||||||
|
|
||||||
// Convert the remaining amount of ZRX to buy into remaining amount
|
// Convert the remaining amount of ZRX to buy into remaining amount
|
||||||
// of WETH to sell, assuming entire amount can be sold in the current order.
|
// of WETH to sell, assuming entire amount can be sold in the current order.
|
||||||
uint256 remainingWethSellAmount = getPartialAmount(
|
uint256 remainingWethSellAmount = getPartialAmountFloor(
|
||||||
orders[i].takerAssetAmount,
|
orders[i].takerAssetAmount,
|
||||||
safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
|
safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees
|
||||||
remainingZrxBuyAmount
|
remainingZrxBuyAmount
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ contract MixinForwarderCore is
|
|||||||
uint256 makerAssetAmountPurchased;
|
uint256 makerAssetAmountPurchased;
|
||||||
if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
|
if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) {
|
||||||
// Calculate amount of WETH that won't be spent on ETH fees.
|
// Calculate amount of WETH that won't be spent on ETH fees.
|
||||||
wethSellAmount = getPartialAmount(
|
wethSellAmount = getPartialAmountFloor(
|
||||||
PERCENTAGE_DENOMINATOR,
|
PERCENTAGE_DENOMINATOR,
|
||||||
safeAdd(PERCENTAGE_DENOMINATOR, feePercentage),
|
safeAdd(PERCENTAGE_DENOMINATOR, feePercentage),
|
||||||
msg.value
|
msg.value
|
||||||
@@ -103,7 +103,7 @@ contract MixinForwarderCore is
|
|||||||
makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
|
makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid);
|
||||||
} else {
|
} else {
|
||||||
// 5% of WETH is reserved for filling feeOrders and paying feeRecipient.
|
// 5% of WETH is reserved for filling feeOrders and paying feeRecipient.
|
||||||
wethSellAmount = getPartialAmount(
|
wethSellAmount = getPartialAmountFloor(
|
||||||
MAX_WETH_FILL_PERCENTAGE,
|
MAX_WETH_FILL_PERCENTAGE,
|
||||||
PERCENTAGE_DENOMINATOR,
|
PERCENTAGE_DENOMINATOR,
|
||||||
msg.value
|
msg.value
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ contract MixinWeth is
|
|||||||
uint256 wethRemaining = safeSub(msg.value, wethSold);
|
uint256 wethRemaining = safeSub(msg.value, wethSold);
|
||||||
|
|
||||||
// Calculate ETH fee to pay to feeRecipient.
|
// Calculate ETH fee to pay to feeRecipient.
|
||||||
uint256 ethFee = getPartialAmount(
|
uint256 ethFee = getPartialAmountFloor(
|
||||||
feePercentage,
|
feePercentage,
|
||||||
PERCENTAGE_DENOMINATOR,
|
PERCENTAGE_DENOMINATOR,
|
||||||
wethSoldExcludingFeeOrders
|
wethSoldExcludingFeeOrders
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ contract MixinExchangeCore is
|
|||||||
|
|
||||||
// Validate fill order rounding
|
// Validate fill order rounding
|
||||||
require(
|
require(
|
||||||
!isRoundingError(
|
!isRoundingErrorFloor(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.makerAssetAmount
|
order.makerAssetAmount
|
||||||
@@ -376,17 +376,17 @@ contract MixinExchangeCore is
|
|||||||
{
|
{
|
||||||
// Compute proportional transfer amounts
|
// Compute proportional transfer amounts
|
||||||
fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
|
fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
|
||||||
fillResults.makerAssetFilledAmount = getPartialAmount(
|
fillResults.makerAssetFilledAmount = getPartialAmountFloor(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.makerAssetAmount
|
order.makerAssetAmount
|
||||||
);
|
);
|
||||||
fillResults.makerFeePaid = getPartialAmount(
|
fillResults.makerFeePaid = getPartialAmountFloor(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.makerFee
|
order.makerFee
|
||||||
);
|
);
|
||||||
fillResults.takerFeePaid = getPartialAmount(
|
fillResults.takerFeePaid = getPartialAmountFloor(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.takerFee
|
order.takerFee
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ contract MixinMatchOrders is
|
|||||||
leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining;
|
||||||
|
|
||||||
// The right order receives an amount proportional to how much was spent.
|
// The right order receives an amount proportional to how much was spent.
|
||||||
rightTakerAssetFilledAmount = getPartialAmount(
|
rightTakerAssetFilledAmount = getPartialAmountFloor(
|
||||||
rightOrder.takerAssetAmount,
|
rightOrder.takerAssetAmount,
|
||||||
rightOrder.makerAssetAmount,
|
rightOrder.makerAssetAmount,
|
||||||
leftTakerAssetFilledAmount
|
leftTakerAssetFilledAmount
|
||||||
@@ -193,7 +193,7 @@ contract MixinMatchOrders is
|
|||||||
rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining;
|
||||||
|
|
||||||
// The left order receives an amount proportional to how much was spent.
|
// The left order receives an amount proportional to how much was spent.
|
||||||
leftTakerAssetFilledAmount = getPartialAmount(
|
leftTakerAssetFilledAmount = getPartialAmountFloor(
|
||||||
rightOrder.makerAssetAmount,
|
rightOrder.makerAssetAmount,
|
||||||
rightOrder.takerAssetAmount,
|
rightOrder.takerAssetAmount,
|
||||||
rightTakerAssetFilledAmount
|
rightTakerAssetFilledAmount
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ contract MixinWrapperFunctions is
|
|||||||
|
|
||||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
|
||||||
orders[i].takerAssetAmount,
|
orders[i].takerAssetAmount,
|
||||||
orders[i].makerAssetAmount,
|
orders[i].makerAssetAmount,
|
||||||
remainingMakerAssetFillAmount
|
remainingMakerAssetFillAmount
|
||||||
@@ -350,7 +350,7 @@ contract MixinWrapperFunctions is
|
|||||||
|
|
||||||
// Convert the remaining amount of makerAsset to buy into remaining amount
|
// Convert the remaining amount of makerAsset to buy into remaining amount
|
||||||
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
// of takerAsset to sell, assuming entire amount can be sold in the current order
|
||||||
uint256 remainingTakerAssetFillAmount = getPartialAmount(
|
uint256 remainingTakerAssetFillAmount = getPartialAmountFloor(
|
||||||
orders[i].takerAssetAmount,
|
orders[i].takerAssetAmount,
|
||||||
orders[i].makerAssetAmount,
|
orders[i].makerAssetAmount,
|
||||||
remainingMakerAssetFillAmount
|
remainingMakerAssetFillAmount
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ contract LibMath is
|
|||||||
SafeMath
|
SafeMath
|
||||||
{
|
{
|
||||||
|
|
||||||
/// @dev Calculates partial value given a numerator and denominator.
|
/// @dev Calculates partial value given a numerator and denominator rounded down.
|
||||||
/// @param numerator Numerator.
|
/// @param numerator Numerator.
|
||||||
/// @param denominator Denominator.
|
/// @param denominator Denominator.
|
||||||
/// @param target Value to calculate partial of.
|
/// @param target Value to calculate partial of.
|
||||||
/// @return Partial value of target rounded down.
|
/// @return Partial value of target rounded down.
|
||||||
function getPartialAmount(
|
function getPartialAmountFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
uint256 target
|
uint256 target
|
||||||
@@ -48,7 +48,7 @@ contract LibMath is
|
|||||||
return partialAmount;
|
return partialAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Calculates partial value given a numerator and denominator.
|
/// @dev Calculates partial value given a numerator and denominator rounded down.
|
||||||
/// @param numerator Numerator.
|
/// @param numerator Numerator.
|
||||||
/// @param denominator Denominator.
|
/// @param denominator Denominator.
|
||||||
/// @param target Value to calculate partial of.
|
/// @param target Value to calculate partial of.
|
||||||
@@ -79,7 +79,7 @@ contract LibMath is
|
|||||||
/// @param denominator Denominator.
|
/// @param denominator Denominator.
|
||||||
/// @param target Value to multiply with numerator/denominator.
|
/// @param target Value to multiply with numerator/denominator.
|
||||||
/// @return Rounding error is present.
|
/// @return Rounding error is present.
|
||||||
function isRoundingError(
|
function isRoundingErrorFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
uint256 target
|
uint256 target
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ contract TestExchangeInternals is
|
|||||||
/// @param denominator Denominator.
|
/// @param denominator Denominator.
|
||||||
/// @param target Value to calculate partial of.
|
/// @param target Value to calculate partial of.
|
||||||
/// @return Partial value of target.
|
/// @return Partial value of target.
|
||||||
function publicGetPartialAmount(
|
function publicGetPartialAmountFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
uint256 target
|
uint256 target
|
||||||
@@ -76,7 +76,7 @@ contract TestExchangeInternals is
|
|||||||
pure
|
pure
|
||||||
returns (uint256 partialAmount)
|
returns (uint256 partialAmount)
|
||||||
{
|
{
|
||||||
return getPartialAmount(numerator, denominator, target);
|
return getPartialAmountFloor(numerator, denominator, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Calculates partial value given a numerator and denominator.
|
/// @dev Calculates partial value given a numerator and denominator.
|
||||||
@@ -101,7 +101,7 @@ contract TestExchangeInternals is
|
|||||||
/// @param denominator Denominator.
|
/// @param denominator Denominator.
|
||||||
/// @param target Value to multiply with numerator/denominator.
|
/// @param target Value to multiply with numerator/denominator.
|
||||||
/// @return Rounding error is present.
|
/// @return Rounding error is present.
|
||||||
function publicIsRoundingError(
|
function publicIsRoundingErrorFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
uint256 target
|
uint256 target
|
||||||
@@ -110,7 +110,7 @@ contract TestExchangeInternals is
|
|||||||
pure
|
pure
|
||||||
returns (bool isError)
|
returns (bool isError)
|
||||||
{
|
{
|
||||||
return isRoundingError(numerator, denominator, target);
|
return isRoundingErrorFloor(numerator, denominator, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Checks if rounding error >= 0.1%.
|
/// @dev Checks if rounding error >= 0.1%.
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ contract TestLibs is
|
|||||||
return fillOrderCalldata;
|
return fillOrderCalldata;
|
||||||
}
|
}
|
||||||
|
|
||||||
function publicGetPartialAmount(
|
function publicGetPartialAmountFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
uint256 target
|
uint256 target
|
||||||
@@ -58,7 +58,7 @@ contract TestLibs is
|
|||||||
pure
|
pure
|
||||||
returns (uint256 partialAmount)
|
returns (uint256 partialAmount)
|
||||||
{
|
{
|
||||||
partialAmount = getPartialAmount(
|
partialAmount = getPartialAmountFloor(
|
||||||
numerator,
|
numerator,
|
||||||
denominator,
|
denominator,
|
||||||
target
|
target
|
||||||
@@ -83,7 +83,7 @@ contract TestLibs is
|
|||||||
return partialAmount;
|
return partialAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function publicIsRoundingError(
|
function publicIsRoundingErrorFloor(
|
||||||
uint256 numerator,
|
uint256 numerator,
|
||||||
uint256 denominator,
|
uint256 denominator,
|
||||||
uint256 target
|
uint256 target
|
||||||
@@ -92,7 +92,7 @@ contract TestLibs is
|
|||||||
pure
|
pure
|
||||||
returns (bool isError)
|
returns (bool isError)
|
||||||
{
|
{
|
||||||
isError = isRoundingError(
|
isError = isRoundingErrorFloor(
|
||||||
numerator,
|
numerator,
|
||||||
denominator,
|
denominator,
|
||||||
target
|
target
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ describe('Exchange core internal functions', () => {
|
|||||||
// Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
|
// Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
|
||||||
// the blockchain state for any tests which modify it!
|
// the blockchain state for any tests which modify it!
|
||||||
|
|
||||||
async function referenceGetPartialAmountAsync(
|
async function referenceGetPartialAmountFloorAsync(
|
||||||
numerator: BigNumber,
|
numerator: BigNumber,
|
||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
@@ -165,18 +165,18 @@ describe('Exchange core internal functions', () => {
|
|||||||
// implementation or the Solidity implementation of
|
// implementation or the Solidity implementation of
|
||||||
// calculateFillResults.
|
// calculateFillResults.
|
||||||
return {
|
return {
|
||||||
makerAssetFilledAmount: await referenceGetPartialAmountAsync(
|
makerAssetFilledAmount: await referenceGetPartialAmountFloorAsync(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
orderTakerAssetAmount,
|
orderTakerAssetAmount,
|
||||||
otherAmount,
|
otherAmount,
|
||||||
),
|
),
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
makerFeePaid: await referenceGetPartialAmountAsync(
|
makerFeePaid: await referenceGetPartialAmountFloorAsync(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
orderTakerAssetAmount,
|
orderTakerAssetAmount,
|
||||||
otherAmount,
|
otherAmount,
|
||||||
),
|
),
|
||||||
takerFeePaid: await referenceGetPartialAmountAsync(
|
takerFeePaid: await referenceGetPartialAmountFloorAsync(
|
||||||
takerAssetFilledAmount,
|
takerAssetFilledAmount,
|
||||||
orderTakerAssetAmount,
|
orderTakerAssetAmount,
|
||||||
otherAmount,
|
otherAmount,
|
||||||
@@ -199,18 +199,18 @@ describe('Exchange core internal functions', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getPartialAmount', async () => {
|
describe('getPartialAmountFloor', async () => {
|
||||||
async function testGetPartialAmountAsync(
|
async function testGetPartialAmountFloorAsync(
|
||||||
numerator: BigNumber,
|
numerator: BigNumber,
|
||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
): Promise<BigNumber> {
|
): Promise<BigNumber> {
|
||||||
return testExchange.publicGetPartialAmount.callAsync(numerator, denominator, target);
|
return testExchange.publicGetPartialAmountFloor.callAsync(numerator, denominator, target);
|
||||||
}
|
}
|
||||||
await testCombinatoriallyWithReferenceFuncAsync(
|
await testCombinatoriallyWithReferenceFuncAsync(
|
||||||
'getPartialAmount',
|
'getPartialAmount',
|
||||||
referenceGetPartialAmountAsync,
|
referenceGetPartialAmountFloorAsync,
|
||||||
testGetPartialAmountAsync,
|
testGetPartialAmountFloorAsync,
|
||||||
[uint256Values, uint256Values, uint256Values],
|
[uint256Values, uint256Values, uint256Values],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -284,7 +284,7 @@ describe('Exchange core internal functions', () => {
|
|||||||
denominator: BigNumber,
|
denominator: BigNumber,
|
||||||
target: BigNumber,
|
target: BigNumber,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return testExchange.publicIsRoundingError.callAsync(numerator, denominator, target);
|
return testExchange.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
}
|
}
|
||||||
await testCombinatoriallyWithReferenceFuncAsync(
|
await testCombinatoriallyWithReferenceFuncAsync(
|
||||||
'isRoundingError',
|
'isRoundingError',
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ describe('Exchange libs', () => {
|
|||||||
const denominator = new BigNumber(999);
|
const denominator = new BigNumber(999);
|
||||||
const target = new BigNumber(50);
|
const target = new BigNumber(50);
|
||||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.true();
|
expect(isRoundingError).to.be.true();
|
||||||
});
|
});
|
||||||
it('should return false if there is a rounding of 0.09%', async () => {
|
it('should return false if there is a rounding of 0.09%', async () => {
|
||||||
@@ -85,7 +85,7 @@ describe('Exchange libs', () => {
|
|||||||
const denominator = new BigNumber(9991);
|
const denominator = new BigNumber(9991);
|
||||||
const target = new BigNumber(500);
|
const target = new BigNumber(500);
|
||||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.false();
|
expect(isRoundingError).to.be.false();
|
||||||
});
|
});
|
||||||
it('should return true if there is a rounding error of 0.11%', async () => {
|
it('should return true if there is a rounding error of 0.11%', async () => {
|
||||||
@@ -93,7 +93,7 @@ describe('Exchange libs', () => {
|
|||||||
const denominator = new BigNumber(9989);
|
const denominator = new BigNumber(9989);
|
||||||
const target = new BigNumber(500);
|
const target = new BigNumber(500);
|
||||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||||
const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target);
|
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.true();
|
expect(isRoundingError).to.be.true();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -467,17 +467,17 @@ export class FillOrderCombinatorialUtils {
|
|||||||
? remainingTakerAmountToFill
|
? remainingTakerAmountToFill
|
||||||
: alreadyFilledTakerAmount.add(takerAssetFillAmount);
|
: alreadyFilledTakerAmount.add(takerAssetFillAmount);
|
||||||
|
|
||||||
const expFilledMakerAmount = orderUtils.getPartialAmount(
|
const expFilledMakerAmount = orderUtils.getPartialAmountFloor(
|
||||||
expFilledTakerAmount,
|
expFilledTakerAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerAssetAmount,
|
signedOrder.makerAssetAmount,
|
||||||
);
|
);
|
||||||
const expMakerFeePaid = orderUtils.getPartialAmount(
|
const expMakerFeePaid = orderUtils.getPartialAmountFloor(
|
||||||
expFilledTakerAmount,
|
expFilledTakerAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
);
|
);
|
||||||
const expTakerFeePaid = orderUtils.getPartialAmount(
|
const expTakerFeePaid = orderUtils.getPartialAmountFloor(
|
||||||
expFilledTakerAmount,
|
expFilledTakerAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.takerFee,
|
signedOrder.takerFee,
|
||||||
@@ -668,7 +668,7 @@ export class FillOrderCombinatorialUtils {
|
|||||||
signedOrder: SignedOrder,
|
signedOrder: SignedOrder,
|
||||||
takerAssetFillAmount: BigNumber,
|
takerAssetFillAmount: BigNumber,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const makerAssetFillAmount = orderUtils.getPartialAmount(
|
const makerAssetFillAmount = orderUtils.getPartialAmountFloor(
|
||||||
takerAssetFillAmount,
|
takerAssetFillAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerAssetAmount,
|
signedOrder.makerAssetAmount,
|
||||||
@@ -705,7 +705,7 @@ export class FillOrderCombinatorialUtils {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const makerFee = orderUtils.getPartialAmount(
|
const makerFee = orderUtils.getPartialAmountFloor(
|
||||||
takerAssetFillAmount,
|
takerAssetFillAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
@@ -829,7 +829,7 @@ export class FillOrderCombinatorialUtils {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const takerFee = orderUtils.getPartialAmount(
|
const takerFee = orderUtils.getPartialAmountFloor(
|
||||||
takerAssetFillAmount,
|
takerAssetFillAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.takerFee,
|
signedOrder.takerFee,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { constants } from './constants';
|
|||||||
import { CancelOrder, MatchOrder } from './types';
|
import { CancelOrder, MatchOrder } from './types';
|
||||||
|
|
||||||
export const orderUtils = {
|
export const orderUtils = {
|
||||||
getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||||
const partialAmount = numerator
|
const partialAmount = numerator
|
||||||
.mul(target)
|
.mul(target)
|
||||||
.div(denominator)
|
.div(denominator)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export class OrderStateUtils {
|
|||||||
const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus(
|
const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus(
|
||||||
sidedOrderRelevantState.filledTakerAssetAmount,
|
sidedOrderRelevantState.filledTakerAssetAmount,
|
||||||
);
|
);
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(
|
||||||
remainingTakerAssetAmount,
|
remainingTakerAssetAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerAssetAmount,
|
signedOrder.makerAssetAmount,
|
||||||
@@ -191,7 +191,7 @@ export class OrderStateUtils {
|
|||||||
);
|
);
|
||||||
const remainingFillableTakerAssetAmountGivenMakersStatus = signedOrder.makerAssetAmount.eq(0)
|
const remainingFillableTakerAssetAmountGivenMakersStatus = signedOrder.makerAssetAmount.eq(0)
|
||||||
? new BigNumber(0)
|
? new BigNumber(0)
|
||||||
: utils.getPartialAmount(
|
: utils.getPartialAmountFloor(
|
||||||
orderRelevantMakerState.remainingFillableAssetAmount,
|
orderRelevantMakerState.remainingFillableAssetAmount,
|
||||||
signedOrder.makerAssetAmount,
|
signedOrder.makerAssetAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export class OrderValidationUtils {
|
|||||||
* @param denominator Denominator value. When used to check an order, pass in `order.takerAssetAmount`
|
* @param denominator Denominator value. When used to check an order, pass in `order.takerAssetAmount`
|
||||||
* @param target Target value. When used to check an order, pass in `order.makerAssetAmount`
|
* @param target Target value. When used to check an order, pass in `order.makerAssetAmount`
|
||||||
*/
|
*/
|
||||||
public static isRoundingError(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
|
public static isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean {
|
||||||
// Solidity's mulmod() in JS
|
// Solidity's mulmod() in JS
|
||||||
// Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions
|
// Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions
|
||||||
if (denominator.eq(0)) {
|
if (denominator.eq(0)) {
|
||||||
@@ -58,7 +58,7 @@ export class OrderValidationUtils {
|
|||||||
zrxAssetData: string,
|
zrxAssetData: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const fillMakerTokenAmount = utils.getPartialAmount(
|
const fillMakerTokenAmount = utils.getPartialAmountFloor(
|
||||||
fillTakerAssetAmount,
|
fillTakerAssetAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerAssetAmount,
|
signedOrder.makerAssetAmount,
|
||||||
@@ -79,7 +79,7 @@ export class OrderValidationUtils {
|
|||||||
TradeSide.Taker,
|
TradeSide.Taker,
|
||||||
TransferType.Trade,
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = utils.getPartialAmount(
|
const makerFeeAmount = utils.getPartialAmountFloor(
|
||||||
fillTakerAssetAmount,
|
fillTakerAssetAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
@@ -92,7 +92,7 @@ export class OrderValidationUtils {
|
|||||||
TradeSide.Maker,
|
TradeSide.Maker,
|
||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
const takerFeeAmount = utils.getPartialAmount(
|
const takerFeeAmount = utils.getPartialAmountFloor(
|
||||||
fillTakerAssetAmount,
|
fillTakerAssetAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.takerFee,
|
signedOrder.takerFee,
|
||||||
@@ -218,7 +218,7 @@ export class OrderValidationUtils {
|
|||||||
zrxAssetData,
|
zrxAssetData,
|
||||||
);
|
);
|
||||||
|
|
||||||
const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingError(
|
const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingErrorFloor(
|
||||||
desiredFillTakerTokenAmount,
|
desiredFillTakerTokenAmount,
|
||||||
signedOrder.takerAssetAmount,
|
signedOrder.takerAssetAmount,
|
||||||
signedOrder.makerAssetAmount,
|
signedOrder.makerAssetAmount,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const utils = {
|
|||||||
const milisecondsInSecond = 1000;
|
const milisecondsInSecond = 1000;
|
||||||
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
return new BigNumber(Date.now() / milisecondsInSecond).round();
|
||||||
},
|
},
|
||||||
getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||||
const fillMakerTokenAmount = numerator
|
const fillMakerTokenAmount = numerator
|
||||||
.mul(target)
|
.mul(target)
|
||||||
.div(denominator)
|
.div(denominator)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe('OrderValidationUtils', () => {
|
|||||||
const denominator = new BigNumber(999);
|
const denominator = new BigNumber(999);
|
||||||
const target = new BigNumber(50);
|
const target = new BigNumber(50);
|
||||||
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.false();
|
expect(isRoundingError).to.be.false();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ describe('OrderValidationUtils', () => {
|
|||||||
const denominator = new BigNumber(9991);
|
const denominator = new BigNumber(9991);
|
||||||
const target = new BigNumber(500);
|
const target = new BigNumber(500);
|
||||||
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.false();
|
expect(isRoundingError).to.be.false();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ describe('OrderValidationUtils', () => {
|
|||||||
const denominator = new BigNumber(9989);
|
const denominator = new BigNumber(9989);
|
||||||
const target = new BigNumber(500);
|
const target = new BigNumber(500);
|
||||||
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.true();
|
expect(isRoundingError).to.be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ describe('OrderValidationUtils', () => {
|
|||||||
const denominator = new BigNumber(7);
|
const denominator = new BigNumber(7);
|
||||||
const target = new BigNumber(10);
|
const target = new BigNumber(10);
|
||||||
// rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67%
|
// rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67%
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.true();
|
expect(isRoundingError).to.be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ describe('OrderValidationUtils', () => {
|
|||||||
const denominator = new BigNumber(2);
|
const denominator = new BigNumber(2);
|
||||||
const target = new BigNumber(10);
|
const target = new BigNumber(10);
|
||||||
|
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.false();
|
expect(isRoundingError).to.be.false();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ describe('OrderValidationUtils', () => {
|
|||||||
const target = new BigNumber(105762562);
|
const target = new BigNumber(105762562);
|
||||||
// rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) /
|
// rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) /
|
||||||
// (76564*105762562/676373677) = 0.0007%
|
// (76564*105762562/676373677) = 0.0007%
|
||||||
const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target);
|
const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target);
|
||||||
expect(isRoundingError).to.be.false();
|
expect(isRoundingError).to.be.false();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user