@0x/contracts-exchange: Make assertValidFill and calculateMatchedFillResults public
This commit is contained in:
committed by
Amir Bandeali
parent
4791c120fe
commit
2f5a1eebe0
@@ -105,6 +105,10 @@
|
||||
{
|
||||
"note": "Add `validatorAddress` field to `SignatureValidatorError` rich reverts",
|
||||
"pr": 1885
|
||||
},
|
||||
{
|
||||
"note": "Make `assertValidFill` and `calculateMatchedFillResults` public",
|
||||
"pr": 1885
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -171,6 +171,66 @@ contract MixinExchangeCore is
|
||||
return orderInfo;
|
||||
}
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
|
||||
function assertValidFill(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo,
|
||||
uint256 takerAssetFillAmount, // TODO: use FillResults
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 makerAssetFilledAmount
|
||||
)
|
||||
public
|
||||
pure
|
||||
{
|
||||
// Revert if fill amount is invalid
|
||||
// TODO: reconsider necessity for v2.1
|
||||
if (takerAssetFillAmount == 0) {
|
||||
_rrevert(FillError(FillErrorCodes.INVALID_TAKER_AMOUNT, orderInfo.orderHash));
|
||||
}
|
||||
|
||||
// Make sure taker does not pay more than desired amount
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
if (takerAssetFilledAmount > takerAssetFillAmount) {
|
||||
_rrevert(FillError(FillErrorCodes.TAKER_OVERPAY, orderInfo.orderHash));
|
||||
}
|
||||
|
||||
// Make sure order is not overfilled
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
if (_safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount)
|
||||
> order.takerAssetAmount) {
|
||||
_rrevert(FillError(FillErrorCodes.OVERFILL, orderInfo.orderHash));
|
||||
}
|
||||
|
||||
// Make sure order is filled at acceptable price.
|
||||
// The order has an implied price from the makers perspective:
|
||||
// order price = order.makerAssetAmount / order.takerAssetAmount
|
||||
// i.e. the number of makerAsset maker is paying per takerAsset. The
|
||||
// maker is guaranteed to get this price or a better (lower) one. The
|
||||
// actual price maker is getting in this fill is:
|
||||
// fill price = makerAssetFilledAmount / takerAssetFilledAmount
|
||||
// We need `fill price <= order price` for the fill to be fair to maker.
|
||||
// This amounts to:
|
||||
// makerAssetFilledAmount order.makerAssetAmount
|
||||
// ------------------------ <= -----------------------
|
||||
// takerAssetFilledAmount order.takerAssetAmount
|
||||
// or, equivalently:
|
||||
// makerAssetFilledAmount * order.takerAssetAmount <=
|
||||
// order.makerAssetAmount * takerAssetFilledAmount
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
if (_safeMul(makerAssetFilledAmount, order.takerAssetAmount)
|
||||
> _safeMul(order.makerAssetAmount, takerAssetFilledAmount)) {
|
||||
_rrevert(FillError(FillErrorCodes.INVALID_FILL_PRICE, orderInfo.orderHash));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
@@ -203,7 +263,7 @@ contract MixinExchangeCore is
|
||||
uint256 takerAssetFilledAmount = _min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Validate context
|
||||
_assertValidFill(
|
||||
assertValidFill(
|
||||
order,
|
||||
orderInfo,
|
||||
takerAssetFillAmount,
|
||||
@@ -372,66 +432,6 @@ contract MixinExchangeCore is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
|
||||
function _assertValidFill(
|
||||
Order memory order,
|
||||
OrderInfo memory orderInfo,
|
||||
uint256 takerAssetFillAmount, // TODO: use FillResults
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 makerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
// Revert if fill amount is invalid
|
||||
// TODO: reconsider necessity for v2.1
|
||||
if (takerAssetFillAmount == 0) {
|
||||
_rrevert(FillError(FillErrorCodes.INVALID_TAKER_AMOUNT, orderInfo.orderHash));
|
||||
}
|
||||
|
||||
// Make sure taker does not pay more than desired amount
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
if (takerAssetFilledAmount > takerAssetFillAmount) {
|
||||
_rrevert(FillError(FillErrorCodes.TAKER_OVERPAY, orderInfo.orderHash));
|
||||
}
|
||||
|
||||
// Make sure order is not overfilled
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
if (_safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount)
|
||||
> order.takerAssetAmount) {
|
||||
_rrevert(FillError(FillErrorCodes.OVERFILL, orderInfo.orderHash));
|
||||
}
|
||||
|
||||
// Make sure order is filled at acceptable price.
|
||||
// The order has an implied price from the makers perspective:
|
||||
// order price = order.makerAssetAmount / order.takerAssetAmount
|
||||
// i.e. the number of makerAsset maker is paying per takerAsset. The
|
||||
// maker is guaranteed to get this price or a better (lower) one. The
|
||||
// actual price maker is getting in this fill is:
|
||||
// fill price = makerAssetFilledAmount / takerAssetFilledAmount
|
||||
// We need `fill price <= order price` for the fill to be fair to maker.
|
||||
// This amounts to:
|
||||
// makerAssetFilledAmount order.makerAssetAmount
|
||||
// ------------------------ <= -----------------------
|
||||
// takerAssetFilledAmount order.takerAssetAmount
|
||||
// or, equivalently:
|
||||
// makerAssetFilledAmount * order.takerAssetAmount <=
|
||||
// order.makerAssetAmount * takerAssetFilledAmount
|
||||
// NOTE: This assertion should never fail, it is here
|
||||
// as an extra defence against potential bugs.
|
||||
if (_safeMul(makerAssetFilledAmount, order.takerAssetAmount)
|
||||
> _safeMul(order.makerAssetAmount, takerAssetFilledAmount)) {
|
||||
_rrevert(FillError(FillErrorCodes.INVALID_FILL_PRICE, orderInfo.orderHash));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Validates context for cancelOrder. Succeeds or throws.
|
||||
/// @param order to be cancelled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
|
||||
@@ -81,7 +81,7 @@ contract MixinMatchOrders is
|
||||
_assertValidMatch(leftOrder, rightOrder);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
matchedFillResults = _calculateMatchedFillResults(
|
||||
matchedFillResults = calculateMatchedFillResults(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
@@ -89,14 +89,14 @@ contract MixinMatchOrders is
|
||||
);
|
||||
|
||||
// Validate fill contexts
|
||||
_assertValidFill(
|
||||
assertValidFill(
|
||||
leftOrder,
|
||||
leftOrderInfo,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
matchedFillResults.left.takerAssetFilledAmount,
|
||||
matchedFillResults.left.makerAssetFilledAmount
|
||||
);
|
||||
_assertValidFill(
|
||||
assertValidFill(
|
||||
rightOrder,
|
||||
rightOrderInfo,
|
||||
matchedFillResults.right.takerAssetFilledAmount,
|
||||
@@ -133,33 +133,6 @@ contract MixinMatchOrders is
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
/// @dev Validates context for matchOrders. Succeeds or throws.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function _assertValidMatch(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// Make sure there is a profitable spread.
|
||||
// There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
|
||||
// than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
|
||||
// This is satisfied by the equations below:
|
||||
// <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
|
||||
// AND
|
||||
// <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
|
||||
// These equations can be combined to get the following:
|
||||
if (_safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) <
|
||||
_safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount)) {
|
||||
_rrevert(NegativeSpreadError(
|
||||
getOrderHash(leftOrder),
|
||||
getOrderHash(rightOrder)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
@@ -169,13 +142,13 @@ contract MixinMatchOrders is
|
||||
/// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function _calculateMatchedFillResults(
|
||||
function calculateMatchedFillResults(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
public
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
@@ -262,6 +235,33 @@ contract MixinMatchOrders is
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
/// @dev Validates context for matchOrders. Succeeds or throws.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
function _assertValidMatch(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder
|
||||
)
|
||||
internal
|
||||
view
|
||||
{
|
||||
// Make sure there is a profitable spread.
|
||||
// There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater
|
||||
// than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount).
|
||||
// This is satisfied by the equations below:
|
||||
// <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount>
|
||||
// AND
|
||||
// <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount>
|
||||
// These equations can be combined to get the following:
|
||||
if (_safeMul(leftOrder.makerAssetAmount, rightOrder.makerAssetAmount) <
|
||||
_safeMul(leftOrder.takerAssetAmount, rightOrder.takerAssetAmount)) {
|
||||
_rrevert(NegativeSpreadError(
|
||||
getOrderHash(leftOrder),
|
||||
getOrderHash(rightOrder)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient.
|
||||
/// @param leftOrderHash First matched order hash.
|
||||
/// @param rightOrderHash Second matched order hash.
|
||||
|
||||
@@ -99,4 +99,20 @@ contract IExchangeCore {
|
||||
public
|
||||
view
|
||||
returns (bytes32 orderHash);
|
||||
|
||||
/// @dev Validates context for fillOrder. Succeeds or throws.
|
||||
/// @param order to be filled.
|
||||
/// @param orderInfo OrderStatus, orderHash, and amount already filled of order.
|
||||
/// @param takerAssetFillAmount Desired amount of order to fill by taker.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param makerAssetFilledAmount Amount of makerAsset that will be transfered.
|
||||
function assertValidFill(
|
||||
LibOrder.Order memory order,
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 takerAssetFillAmount, // TODO: use FillResults
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 makerAssetFilledAmount
|
||||
)
|
||||
public
|
||||
pure;
|
||||
}
|
||||
|
||||
@@ -42,4 +42,23 @@ contract IMatchOrders {
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
|
||||
/// @dev Calculates fill amounts for the matched orders.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the leftOrder order goes to the taker (who matched the two orders).
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
function calculateMatchedFillResults(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user