aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/src/2.0.0/forwarder/MixinExpectedResults.sol
blob: 0bca7dc8053b0f2598ab6432625aa168670783fe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*

  Copyright 2018 ZeroEx Intl.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import "../utils/LibBytes/LibBytes.sol";
import "../protocol/Exchange/libs/LibFillResults.sol";
import "../protocol/Exchange/libs/LibMath.sol";
import "../protocol/Exchange/libs/LibOrder.sol";
import "./MixinConstants.sol";

contract MixinExpectedResults is
    LibMath,
    LibFillResults,
    MixinConstants
{

    /// @dev Simulates the 0x Exchange fillOrder validation and calculations, without performing any state changes.
    /// @param order An Order struct containing order specifications.
    /// @param takerAssetFillAmount A number representing the amount of this order to fill.
    /// @return fillResults Amounts filled and fees paid by maker and taker.
    function calculateFillResults(
        LibOrder.Order memory order,
        uint256 takerAssetFillAmount
    )
        internal
        view
        returns (FillResults memory fillResults)
    {
        LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(order);
        if (orderInfo.orderStatus != uint8(LibOrder.OrderStatus.FILLABLE)) {
            return fillResults;
        }
        uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount);
        uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount);

        fillResults.takerAssetFilledAmount = takerAssetFilledAmount;
        fillResults.makerAssetFilledAmount = getPartialAmount(
            takerAssetFilledAmount,
            order.takerAssetAmount,
            order.makerAssetAmount
        );
        fillResults.makerFeePaid = getPartialAmount(
            takerAssetFilledAmount,
            order.takerAssetAmount,
            order.makerFee
        );
        fillResults.takerFeePaid = getPartialAmount(
            takerAssetFilledAmount,
            order.takerAssetAmount,
            order.takerFee
        );
        return fillResults;
    }

    /// @dev Calculates a FillResults total for selling takerAssetFillAmount over all orders. 
    ///      Including the fees required to be paid. 
    /// @param orders An array of Order struct containing order specifications.
    /// @param takerAssetFillAmount A number representing the amount of this order to fill.
    /// @return totalFillResults Amounts filled and fees paid by maker and taker.
    function calculateMarketSellResults(
        LibOrder.Order[] memory orders,
        uint256 takerAssetFillAmount
    )
        internal
        view
        returns (FillResults memory totalFillResults)
    {
        for (uint256 i = 0; i < orders.length; i++) {
            uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
            FillResults memory singleFillResult = calculateFillResults(orders[i], remainingTakerAssetFillAmount);
            addFillResults(totalFillResults, singleFillResult);
            if (totalFillResults.takerAssetFilledAmount == takerAssetFillAmount) {
                break;
            }
        }
        return totalFillResults;
    }

    /// @dev Calculates a total FillResults for buying makerAssetFillAmount over all orders.
    ///      Including the fees required to be paid. 
    /// @param orders An array of Order struct containing order specifications.
    /// @param makerAssetFillAmount A number representing the amount of this order to fill.
    /// @return totalFillResults Amounts filled and fees paid by maker and taker.
    function calculateMarketBuyResults(
        LibOrder.Order[] memory orders,
        uint256 makerAssetFillAmount
    )
        public
        view
        returns (FillResults memory totalFillResults)
    {
        for (uint256 i = 0; i < orders.length; i++) {
            uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
            uint256 remainingTakerAssetFillAmount = getPartialAmount(
                orders[i].takerAssetAmount,
                orders[i].makerAssetAmount,
                remainingMakerAssetFillAmount
            );
            FillResults memory singleFillResult = calculateFillResults(orders[i], remainingTakerAssetFillAmount);
            addFillResults(totalFillResults, singleFillResult);
            if (totalFillResults.makerAssetFilledAmount == makerAssetFillAmount) {
                break;
            }
        }
        return totalFillResults;
    }

    /// @dev Calculates fill results for buyFeeTokens. This handles fees on buying ZRX
    ///      so the end result is the expected amount of ZRX (not less after fees).
    /// @param orders An array of Order struct containing order specifications.
    /// @param zrxFillAmount A number representing the amount zrx to buy
    /// @return totalFillResults Expected fill result amounts from buying fees
    function calculateMarketBuyZrxResults(
        LibOrder.Order[] memory orders,
        uint256 zrxFillAmount
    )
        public
        view
        returns (FillResults memory totalFillResults)
    {
        for (uint256 i = 0; i < orders.length; i++) {
            uint256 remainingZrxFillAmount = safeSub(zrxFillAmount, totalFillResults.makerAssetFilledAmount);
            // Convert the remaining amount of makerToken to buy into remaining amount
            // of takerToken to sell, assuming entire amount can be sold in the current order
            uint256 remainingWethSellAmount = getPartialAmount(
                orders[i].takerAssetAmount,
                safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees 
                remainingZrxFillAmount
            );
            FillResults memory singleFillResult = calculateFillResults(orders[i], safeAdd(remainingWethSellAmount, 1));

            singleFillResult.makerAssetFilledAmount = safeSub(singleFillResult.makerAssetFilledAmount, singleFillResult.takerFeePaid);
            addFillResults(totalFillResults, singleFillResult);
            // As we compensate for the rounding issue above have slightly more ZRX than the requested zrxFillAmount
            if (totalFillResults.makerAssetFilledAmount >= zrxFillAmount) {
                break;
            }
        }
        return totalFillResults;
    }
}