slightly restructure contracts to fix bug in the WETH-fee case

This commit is contained in:
Michael Zhu 2019-07-12 14:48:53 -07:00
parent 7ff7e9d2e7
commit 1b8a9e16e2
3 changed files with 93 additions and 49 deletions

View File

@ -89,11 +89,13 @@ contract MixinExchangeWrapper is
bytes[] memory signatures
)
internal
returns (FillResults memory totalFillResults)
returns (
FillResults memory totalFillResults,
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{
uint256 ordersLength = orders.length;
// The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = wethSellAmount;
for (uint256 i = 0; i != ordersLength; i++) {
require(
@ -101,34 +103,62 @@ contract MixinExchangeWrapper is
"MAKER_ASSET_MISMATCH"
);
// The remaining amount of WETH to sell
uint256 remainingTakerAssetFillAmount = _safeSub(
wethSellAmount,
wethSpentAmount
);
FillResults memory singleFillResults;
// Update amounts filled and the remaining amount of WETH to sell
if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) {
// Attempt to sell the remaining amount of WETH
FillResults memory singleFillResults = _fillOrderNoThrow(
singleFillResults = _fillOrderNoThrow(
orders[i],
remainingTakerAssetFillAmount,
signatures[i]
);
// Update amounts filled and the remaining amount of WETH to sell
if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) {
_addFillResultsDeductFees(totalFillResults, singleFillResults);
} else {
_addFillResults(totalFillResults, singleFillResults);
remainingTakerAssetFillAmount = _safeSub(
remainingTakerAssetFillAmount,
singleFillResults.takerFeePaid
makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
_safeSub(singleFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid)
);
}
remainingTakerAssetFillAmount = _safeSub(
remainingTakerAssetFillAmount,
wethSpentAmount = _safeAdd(
wethSpentAmount,
singleFillResults.takerAssetFilledAmount
);
} else {
// We first sell WETH as the takerAsset, then use it to pay the takerFee.
// This ensures that we reserve enough to pay the fee.
uint256 takerAssetFillAmount = _getPartialAmountCeil(
orders[i].takerAssetAmount,
_safeAdd(orders[i].takerAssetAmount, orders[i].takerFee),
remainingTakerAssetFillAmount
);
singleFillResults = _fillOrderNoThrow(
orders[i],
takerAssetFillAmount,
signatures[i]
);
wethSpentAmount = _safeAdd(
wethSpentAmount,
_safeAdd(singleFillResults.takerAssetFilledAmount, singleFillResults.takerFeePaid)
);
makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
singleFillResults.makerAssetFilledAmount
);
}
_addFillResults(totalFillResults, singleFillResults);
// Stop execution if the entire amount of takerAsset has been sold
if (totalFillResults.takerAssetFilledAmount >= wethSellAmount) {
if (wethSpentAmount >= wethSellAmount) {
break;
}
}
return totalFillResults;
return (totalFillResults, wethSpentAmount, makerAssetAcquiredAmount);
}
/// @dev Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker.
@ -144,10 +174,13 @@ contract MixinExchangeWrapper is
bytes[] memory signatures
)
internal
returns (FillResults memory totalFillResults)
returns (
FillResults memory totalFillResults,
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount
)
{
uint256 ordersLength = orders.length;
uint256 makerAssetFilledAmount = 0;
for (uint256 i = 0; i != ordersLength; i++) {
require(
@ -156,7 +189,7 @@ contract MixinExchangeWrapper is
);
// Calculate the remaining amount of makerAsset to buy
uint256 remainingMakerAssetFillAmount = _safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
uint256 remainingMakerAssetFillAmount = _safeSub(makerAssetFillAmount, makerAssetAcquiredAmount);
// 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.
@ -177,22 +210,36 @@ contract MixinExchangeWrapper is
// Update amounts filled and fees paid by maker and taker
if (orders[i].makerAssetData.equals(orders[i].takerFeeAssetData)) {
_addFillResultsDeductFees(totalFillResults, singleFillResults);
makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
_safeSub(singleFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid)
);
wethSpentAmount = _safeAdd(
wethSpentAmount,
singleFillResults.takerAssetFilledAmount
);
} else {
_addFillResults(totalFillResults, singleFillResults);
makerAssetAcquiredAmount = _safeAdd(
makerAssetAcquiredAmount,
_safeSub(singleFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid)
);
wethSpentAmount = _safeAdd(
wethSpentAmount,
singleFillResults.takerAssetFilledAmount
);
}
_addFillResults(totalFillResults, singleFillResults);
// Stop execution if the entire amount of makerAsset has been bought
makerAssetFilledAmount = totalFillResults.makerAssetFilledAmount;
if (makerAssetFilledAmount >= makerAssetFillAmount) {
if (makerAssetAcquiredAmount >= makerAssetFillAmount) {
break;
}
}
require(
makerAssetFilledAmount >= makerAssetFillAmount,
makerAssetAcquiredAmount >= makerAssetFillAmount,
"COMPLETE_FILL_FAILED"
);
return totalFillResults;
return (totalFillResults, wethSpentAmount, makerAssetAcquiredAmount);
}
}

View File

@ -88,7 +88,13 @@ contract MixinForwarderCore is
// Market sell 95% of WETH.
// ZRX fees are payed with this contract's balance.
orderFillResults = _marketSellWeth(
uint256 wethSpentAmount;
uint256 makerAssetAcquiredAmount;
(
orderFillResults,
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketSellWeth(
orders,
wethSellAmount,
signatures
@ -97,7 +103,7 @@ contract MixinForwarderCore is
// Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
// Refund remaining ETH to msg.sender.
_transferEthFeeAndRefund(
orderFillResults.takerAssetFilledAmount,
wethSpentAmount,
feePercentage,
feeRecipient
);
@ -105,7 +111,7 @@ contract MixinForwarderCore is
// Transfer purchased assets to msg.sender.
_transferAssetToSender(
orders[0].makerAssetData,
orderFillResults.makerAssetFilledAmount
makerAssetAcquiredAmount
);
}
@ -136,7 +142,13 @@ contract MixinForwarderCore is
// Attempt to purchase desired amount of makerAsset.
// ZRX fees are payed with this contract's balance.
orderFillResults = _marketBuyExactAmountWithWeth(
uint256 wethSpentAmount;
uint256 makerAssetAcquiredAmount;
(
orderFillResults,
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketBuyExactAmountWithWeth(
orders,
makerAssetFillAmount,
signatures
@ -145,7 +157,7 @@ contract MixinForwarderCore is
// Transfer feePercentage of total ETH spent on primary orders to feeRecipient.
// Refund remaining ETH to msg.sender.
_transferEthFeeAndRefund(
orderFillResults.takerAssetFilledAmount,
wethSpentAmount,
feePercentage,
feeRecipient
);
@ -153,7 +165,7 @@ contract MixinForwarderCore is
// Transfer purchased assets to msg.sender.
_transferAssetToSender(
orders[0].makerAssetData,
orderFillResults.makerAssetFilledAmount
makerAssetAcquiredAmount
);
}
}

View File

@ -402,19 +402,4 @@ library LibFillResults {
return matchedFillResults;
}
/// @dev Adds properties of both FillResults instances.
/// Modifies the first FillResults instance specified.
/// @param totalFillResults Fill results instance that will be added onto.
/// @param singleFillResults Fill results instance that will be added to totalFillResults.
function _addFillResultsDeductFees(FillResults memory totalFillResults, FillResults memory singleFillResults)
internal
pure
{
totalFillResults.makerAssetFilledAmount = _safeAdd(totalFillResults.makerAssetFilledAmount, singleFillResults.makerAssetFilledAmount);
totalFillResults.takerAssetFilledAmount = _safeAdd(totalFillResults.takerAssetFilledAmount, singleFillResults.takerAssetFilledAmount);
// The fee amount must be deducted from the amount transfered back to sender.
totalFillResults.makerAssetFilledAmount = _safeSub(totalFillResults.makerAssetFilledAmount, singleFillResults.takerFeePaid);
}
}