diff options
author | Fabio Berger <me@fabioberger.com> | 2018-08-27 22:28:57 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-08-27 22:28:57 +0800 |
commit | b8241c0f808518a3f727424cacb952cc9ce80c4c (patch) | |
tree | 309abba264ea3578cefdc8d7a4f53ef482ff26c9 /packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | |
parent | fe7a8be98c32c6aed8548574e67e36962db732fb (diff) | |
parent | f4a4fefe422a5b2140d5bb394a7f06f842352c69 (diff) | |
download | dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.tar dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.tar.gz dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.tar.bz2 dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.tar.lz dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.tar.xz dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.tar.zst dexon-sol-tools-b8241c0f808518a3f727424cacb952cc9ce80c4c.zip |
Merge branch 'development' into dev-dropdown
* development: (120 commits)
Exit with non-error code at end of publishRelease
Publish
Updated CHANGELOGS
Fix prettier
Update changelog files for RC packages
Skip doc generation for local publishes since we test this in a separate CI test
Fix typo
Use absolute path
Run yarn a second time if the first fails
Try relative to root dir
Fix command
Move md files to lib folder during build
Change exit code to failure
Fix sra-spec `main` and `types` in package.json
Actual relative path
Try relative path
Issue #1025 BlockParam unroll
Fix command
Move md files to lib folder during build
Fix sra-spec `main` and `types` in package.json
...
Diffstat (limited to 'packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol')
-rw-r--r-- | packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | 132 |
1 files changed, 84 insertions, 48 deletions
diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 56b309a1b..075a610b5 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -14,6 +14,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; +import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibConstants.sol"; import "./libs/LibMath.sol"; import "./libs/LibOrder.sol"; @@ -25,6 +26,7 @@ import "./mixins/MAssetProxyDispatcher.sol"; contract MixinMatchOrders is + ReentrancyGuard, LibConstants, LibMath, MAssetProxyDispatcher, @@ -48,6 +50,7 @@ contract MixinMatchOrders is bytes memory rightSignature ) public + nonReentrant returns (LibFillResults.MatchedFillResults memory matchedFillResults) { // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData. @@ -61,8 +64,20 @@ contract MixinMatchOrders is // Fetch taker address address takerAddress = getCurrentContextAddress(); - + // Either our context is valid or we revert + assertFillableOrder( + leftOrder, + leftOrderInfo, + takerAddress, + leftSignature + ); + assertFillableOrder( + rightOrder, + rightOrderInfo, + takerAddress, + rightSignature + ); assertValidMatch(leftOrder, rightOrder); // Compute proportional fill amounts @@ -77,20 +92,18 @@ contract MixinMatchOrders is assertValidFill( leftOrder, leftOrderInfo, - takerAddress, matchedFillResults.left.takerAssetFilledAmount, matchedFillResults.left.takerAssetFilledAmount, - leftSignature + matchedFillResults.left.makerAssetFilledAmount ); assertValidFill( rightOrder, rightOrderInfo, - takerAddress, matchedFillResults.right.takerAssetFilledAmount, matchedFillResults.right.takerAssetFilledAmount, - rightSignature + matchedFillResults.right.makerAssetFilledAmount ); - + // Update exchange state updateFilledState( leftOrder, @@ -106,7 +119,7 @@ contract MixinMatchOrders is rightOrderInfo.orderTakerAssetFilledAmount, matchedFillResults.right ); - + // Settle matched orders. Succeeds or throws. settleMatchedOrders( leftOrder, @@ -162,62 +175,85 @@ contract MixinMatchOrders is pure returns (LibFillResults.MatchedFillResults memory matchedFillResults) { - // We settle orders at the exchange rate of the right order. - // The amount saved by the left maker goes to the taker. - // Either the left or right order will be fully filled; possibly both. - // The left order is fully filled iff the right order can sell more than left can buy. - // That is: the amount required to fill the left order is less than or equal to - // the amount we can spend from the right order: - // <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightMakerToTakerRatio> - // <leftTakerAssetAmountRemaining> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> - // <leftTakerAssetAmountRemaining> * <rightOrder.takerAssetAmount> <= <rightTakerAssetAmountRemaining> * <rightOrder.makerAssetAmount> + // Derive maker asset amounts for left & right orders, given store taker assert amounts uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount); + uint256 leftMakerAssetAmountRemaining = getPartialAmountFloor( + leftOrder.makerAssetAmount, + leftOrder.takerAssetAmount, + leftTakerAssetAmountRemaining + ); uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount); - uint256 leftTakerAssetFilledAmount; - uint256 rightTakerAssetFilledAmount; - if ( - safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <= - safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount) - ) { - // Left order will be fully filled: maximally fill left - leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining; + uint256 rightMakerAssetAmountRemaining = getPartialAmountFloor( + rightOrder.makerAssetAmount, + rightOrder.takerAssetAmount, + rightTakerAssetAmountRemaining + ); - // The right order receives an amount proportional to how much was spent. - rightTakerAssetFilledAmount = getPartialAmount( - rightOrder.takerAssetAmount, - rightOrder.makerAssetAmount, - leftTakerAssetFilledAmount + // Calculate fill results for maker and taker assets: at least one order will be fully filled. + // The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining` + // The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining` + // We have two distinct cases for calculating the fill results: + // Case 1. + // If the left maker can buy more than the right maker can sell, then only the right order is fully filled. + // If the left maker can buy exactly what the right maker can sell, then both orders are fully filled. + // Case 2. + // If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled. + if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) { + // Case 1: Right order is fully filled + matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; + matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; + matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount; + // Round down to ensure the maker's exchange rate does not exceed the price specified by the order. + // We favor the maker when the exchange rate must be rounded. + matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor( + leftOrder.makerAssetAmount, + leftOrder.takerAssetAmount, + matchedFillResults.left.takerAssetFilledAmount ); } else { - // Right order will be fully filled: maximally fill right - rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining; - - // The left order receives an amount proportional to how much was spent. - leftTakerAssetFilledAmount = getPartialAmount( - rightOrder.makerAssetAmount, + // Case 2: Left order is fully filled + matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; + matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; + matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount; + // Round up to ensure the maker's exchange rate does not exceed the price specified by the order. + // We favor the maker when the exchange rate must be rounded. + matchedFillResults.right.takerAssetFilledAmount = getPartialAmountCeil( rightOrder.takerAssetAmount, - rightTakerAssetFilledAmount + rightOrder.makerAssetAmount, + matchedFillResults.right.makerAssetFilledAmount ); } - // Calculate fill results for left order - matchedFillResults.left = calculateFillResults( - leftOrder, - leftTakerAssetFilledAmount - ); - - // Calculate fill results for right order - matchedFillResults.right = calculateFillResults( - rightOrder, - rightTakerAssetFilledAmount - ); - // Calculate amount given to taker matchedFillResults.leftMakerAssetSpreadAmount = safeSub( matchedFillResults.left.makerAssetFilledAmount, matchedFillResults.right.takerAssetFilledAmount ); + // Compute fees for left order + matchedFillResults.left.makerFeePaid = getPartialAmountFloor( + matchedFillResults.left.makerAssetFilledAmount, + leftOrder.makerAssetAmount, + leftOrder.makerFee + ); + matchedFillResults.left.takerFeePaid = getPartialAmountFloor( + matchedFillResults.left.takerAssetFilledAmount, + leftOrder.takerAssetAmount, + leftOrder.takerFee + ); + + // Compute fees for right order + matchedFillResults.right.makerFeePaid = getPartialAmountFloor( + matchedFillResults.right.makerAssetFilledAmount, + rightOrder.makerAssetAmount, + rightOrder.makerFee + ); + matchedFillResults.right.takerFeePaid = getPartialAmountFloor( + matchedFillResults.right.takerAssetFilledAmount, + rightOrder.takerAssetAmount, + rightOrder.takerFee + ); + // Return fill results return matchedFillResults; } |