@dolomite-exchange/dolomite-margin 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/build/contracts/Account.json +11 -11
  2. package/build/contracts/Actions.json +11 -11
  3. package/build/contracts/Address.json +1 -1
  4. package/build/contracts/Admin.json +23 -23
  5. package/build/contracts/AdminImpl.json +35 -307
  6. package/build/contracts/AdvancedMath.json +7 -7
  7. package/build/contracts/AmmRebalancerProxy.json +577 -621
  8. package/build/contracts/AmmRebalancerProxyV1.json +78 -32
  9. package/build/contracts/Babylonian.json +1 -1
  10. package/build/contracts/Bits.json +9 -9
  11. package/build/contracts/Cache.json +13 -13
  12. package/build/contracts/ChainlinkPriceOracleV1.json +16 -16
  13. package/build/contracts/Context.json +1 -1
  14. package/build/contracts/CustomTestToken.json +9 -9
  15. package/build/contracts/Decimal.json +9 -9
  16. package/build/contracts/DelayedMultiSig.json +9 -9
  17. package/build/contracts/DolomiteAmmERC20.json +11 -11
  18. package/build/contracts/DolomiteAmmFactory.json +14 -52
  19. package/build/contracts/DolomiteAmmLibrary.json +24 -24
  20. package/build/contracts/DolomiteAmmPair.json +27 -27
  21. package/build/contracts/DolomiteAmmRouterProxy.json +30 -363
  22. package/build/contracts/DolomiteMargin.json +21 -67
  23. package/build/contracts/DoubleExponentInterestSetter.json +15 -21
  24. package/build/contracts/EnumerableSet.json +7 -7
  25. package/build/contracts/ErroringOmiseToken.json +9 -9
  26. package/build/contracts/ErroringToken.json +10 -10
  27. package/build/contracts/Events.json +17 -17
  28. package/build/contracts/ExcessivelySafeCall.json +35 -35
  29. package/build/contracts/Exchange.json +15 -15
  30. package/build/contracts/Expiry.json +36 -36
  31. package/build/contracts/Getters.json +33 -33
  32. package/build/contracts/IAutoTrader.json +9 -9
  33. package/build/contracts/ICallee.json +7 -7
  34. package/build/contracts/IChainlinkAggregator.json +5 -5
  35. package/build/contracts/IDolomiteAmmERC20.json +5 -5
  36. package/build/contracts/IDolomiteAmmFactory.json +9 -9
  37. package/build/contracts/IDolomiteAmmPair.json +9 -9
  38. package/build/contracts/IDolomiteMargin.json +23 -23
  39. package/build/contracts/IERC20.json +1 -1
  40. package/build/contracts/IERC20Detailed.json +5 -5
  41. package/build/contracts/IExchangeWrapper.json +5 -5
  42. package/build/contracts/IExpiry.json +9 -9
  43. package/build/contracts/IInterestSetter.json +7 -7
  44. package/build/contracts/ILiquidationCallback.json +7 -7
  45. package/build/contracts/IMakerOracle.json +5 -5
  46. package/build/contracts/IOasisDex.json +5 -5
  47. package/build/contracts/IPriceOracle.json +7 -7
  48. package/build/contracts/IRecyclable.json +9 -9
  49. package/build/contracts/ITransferProxy.json +5 -5
  50. package/build/contracts/IUniswapV2Callee.json +5 -5
  51. package/build/contracts/IUniswapV2Factory.json +5 -5
  52. package/build/contracts/IUniswapV2Pair.json +5 -5
  53. package/build/contracts/IUniswapV2Router.json +5 -5
  54. package/build/contracts/IWETH.json +5 -5
  55. package/build/contracts/Interest.json +15 -15
  56. package/build/contracts/LiquidateOrVaporizeImpl.json +32 -83
  57. package/build/contracts/LiquidatorProxyHelper.json +23 -23
  58. package/build/contracts/LiquidatorProxyV1.json +30 -36
  59. package/build/contracts/LiquidatorProxyV1WithAmm.json +49 -105
  60. package/build/contracts/Math.json +1 -1
  61. package/build/contracts/Migrations.json +8 -14
  62. package/build/contracts/Monetary.json +7 -7
  63. package/build/contracts/MultiCall.json +8 -14
  64. package/build/contracts/MultiSig.json +7 -7
  65. package/build/contracts/OmiseToken.json +8 -8
  66. package/build/contracts/OnlyDolomiteMargin.json +11 -11
  67. package/build/contracts/Operation.json +15 -15
  68. package/build/contracts/OperationImpl.json +39 -47
  69. package/build/contracts/Ownable.json +1 -1
  70. package/build/contracts/PartiallyDelayedMultiSig.json +9 -9
  71. package/build/contracts/PayableProxy.json +17 -23
  72. package/build/contracts/Permission.json +11 -11
  73. package/build/contracts/PolynomialInterestSetter.json +13 -13
  74. package/build/contracts/RecyclableTokenProxy.json +25 -25
  75. package/build/contracts/ReentrancyGuard.json +1 -1
  76. package/build/contracts/Require.json +7 -7
  77. package/build/contracts/SafeERC20.json +1 -1
  78. package/build/contracts/SafeETH.json +7 -7
  79. package/build/contracts/SafeLiquidationCallback.json +17 -17
  80. package/build/contracts/SafeMath.json +1 -1
  81. package/build/contracts/SignedOperationProxy.json +21 -104
  82. package/build/contracts/SimpleFeeOwner.json +18 -63
  83. package/build/contracts/State.json +9 -9
  84. package/build/contracts/Storage.json +37 -37
  85. package/build/contracts/TestAmmRebalancerProxy.json +32 -58
  86. package/build/contracts/TestAutoTrader.json +22 -22
  87. package/build/contracts/TestBtcUsdChainlinkAggregator.json +10 -10
  88. package/build/contracts/TestCallee.json +19 -19
  89. package/build/contracts/TestChainlinkPriceOracleV1.json +10 -94
  90. package/build/contracts/TestCounter.json +7 -7
  91. package/build/contracts/TestDaiUsdChainlinkAggregator.json +11 -11
  92. package/build/contracts/TestDolomiteMargin.json +22 -22
  93. package/build/contracts/TestDoubleExponentInterestSetter.json +10 -10
  94. package/build/contracts/TestEthUsdChainlinkAggregator.json +11 -11
  95. package/build/contracts/TestExchangeWrapper.json +28 -28
  96. package/build/contracts/TestInterestSetter.json +13 -13
  97. package/build/contracts/TestLib.json +22 -22
  98. package/build/contracts/TestLinkUsdChainlinkAggregator.json +11 -11
  99. package/build/contracts/TestLiquidateCallback.json +719 -719
  100. package/build/contracts/TestLiquidationCallback.json +13 -13
  101. package/build/contracts/TestLrcEthChainlinkAggregator.json +11 -11
  102. package/build/contracts/TestMakerOracle.json +10 -10
  103. package/build/contracts/TestMaticUsdChainlinkAggregator.json +10 -10
  104. package/build/contracts/TestOasisDex.json +12 -12
  105. package/build/contracts/TestOperationImpl.json +14 -14
  106. package/build/contracts/TestPolynomialInterestSetter.json +10 -10
  107. package/build/contracts/TestPriceAggregator.json +9 -9
  108. package/build/contracts/TestPriceOracle.json +13 -13
  109. package/build/contracts/TestRecyclableToken.json +9 -9
  110. package/build/contracts/TestSimpleCallee.json +15 -15
  111. package/build/contracts/TestToken.json +9 -9
  112. package/build/contracts/TestTrader.json +17 -17
  113. package/build/contracts/TestUniswapAmmRebalancerProxy.json +16 -16
  114. package/build/contracts/TestUsdcUsdChainlinkAggregator.json +11 -11
  115. package/build/contracts/TestWETH.json +9 -9
  116. package/build/contracts/Time.json +9 -9
  117. package/build/contracts/Token.json +9 -9
  118. package/build/contracts/TokenA.json +10 -10
  119. package/build/contracts/TokenB.json +10 -10
  120. package/build/contracts/TokenC.json +10 -10
  121. package/build/contracts/TokenD.json +10 -10
  122. package/build/contracts/TokenE.json +10 -10
  123. package/build/contracts/TokenF.json +10 -10
  124. package/build/contracts/TransferProxy.json +22 -28
  125. package/build/contracts/TypedSignature.json +9 -9
  126. package/build/contracts/Types.json +9 -9
  127. package/build/contracts/UQ112x112.json +7 -7
  128. package/build/contracts/UniswapV2ERC20.json +7 -7
  129. package/build/contracts/UniswapV2Factory.json +12 -12
  130. package/build/contracts/UniswapV2Library.json +20 -20
  131. package/build/contracts/UniswapV2Pair.json +17 -17
  132. package/build/contracts/UniswapV2Router02.json +16 -16
  133. package/build/contracts/WETH9.json +1 -1
  134. package/contracts/external/amm/DolomiteAmmERC20.sol +135 -0
  135. package/contracts/external/amm/DolomiteAmmFactory.sol +122 -0
  136. package/contracts/external/amm/DolomiteAmmPair.sol +573 -0
  137. package/contracts/external/amm/SimpleFeeOwner.sol +107 -0
  138. package/contracts/external/helpers/LiquidatorProxyHelper.sol +252 -0
  139. package/contracts/external/helpers/OnlyDolomiteMargin.sol +63 -0
  140. package/contracts/external/interestsetters/DoubleExponentInterestSetter.sol +212 -0
  141. package/contracts/external/interestsetters/PolynomialInterestSetter.sol +205 -0
  142. package/contracts/external/interfaces/IChainlinkAggregator.sol +33 -0
  143. package/contracts/external/interfaces/IDolomiteAmmERC20.sol +52 -0
  144. package/contracts/external/interfaces/IDolomiteAmmFactory.sol +42 -0
  145. package/contracts/external/interfaces/IDolomiteAmmPair.sol +116 -0
  146. package/contracts/external/interfaces/IExpiry.sol +70 -0
  147. package/contracts/external/interfaces/IMakerOracle.sol +52 -0
  148. package/contracts/external/interfaces/IOasisDex.sol +326 -0
  149. package/contracts/external/interfaces/ITransferProxy.sol +53 -0
  150. package/contracts/external/interfaces/IUniswapV2Router.sol +134 -0
  151. package/contracts/external/lib/AdvancedMath.sol +23 -0
  152. package/contracts/external/lib/DolomiteAmmLibrary.sol +323 -0
  153. package/contracts/external/lib/TypedSignature.sol +120 -0
  154. package/contracts/external/lib/UQ112x112.sol +22 -0
  155. package/contracts/external/multisig/DelayedMultiSig.sol +206 -0
  156. package/contracts/external/multisig/MultiSig.sol +571 -0
  157. package/contracts/external/multisig/PartiallyDelayedMultiSig.sol +174 -0
  158. package/contracts/external/oracles/ChainlinkPriceOracleV1.sol +197 -0
  159. package/contracts/external/oracles/TestChainlinkPriceOracleV1.sol +98 -0
  160. package/contracts/external/proxies/AmmRebalancerProxyV1.sol +465 -0
  161. package/contracts/external/proxies/DolomiteAmmRouterProxy.sol +877 -0
  162. package/contracts/external/proxies/LiquidatorProxyV1.sol +507 -0
  163. package/contracts/external/proxies/LiquidatorProxyV1WithAmm.sol +574 -0
  164. package/contracts/external/proxies/PayableProxy.sol +146 -0
  165. package/contracts/external/proxies/RecyclableTokenProxy.sol +463 -0
  166. package/contracts/external/proxies/SignedOperationProxy.sol +553 -0
  167. package/contracts/external/proxies/TransferProxy.sol +207 -0
  168. package/contracts/external/traders/Expiry.sol +532 -0
  169. package/contracts/external/uniswap-v2/UniswapV2ERC20.sol +118 -0
  170. package/contracts/external/uniswap-v2/UniswapV2Factory.sol +67 -0
  171. package/contracts/external/uniswap-v2/UniswapV2Pair.sol +283 -0
  172. package/contracts/external/uniswap-v2/UniswapV2Router02.sol +566 -0
  173. package/contracts/external/uniswap-v2/interfaces/IUniswapV2Callee.sol +13 -0
  174. package/contracts/external/uniswap-v2/interfaces/IUniswapV2Factory.sol +18 -0
  175. package/contracts/external/uniswap-v2/interfaces/IUniswapV2Pair.sol +67 -0
  176. package/contracts/external/uniswap-v2/interfaces/IWETH.sol +7 -0
  177. package/contracts/external/uniswap-v2/libraries/SafeETH.sol +29 -0
  178. package/contracts/external/uniswap-v2/libraries/UniswapV2Library.sol +117 -0
  179. package/contracts/external/utils/MultiCall.sol +95 -0
  180. package/contracts/protocol/impl/artifacts/OperationImpl.json +80 -0
  181. package/contracts/protocol/impl/artifacts/OperationImpl_metadata.json +193 -0
  182. package/dist/build/published_contracts/AdminImpl.json +2 -2
  183. package/dist/build/published_contracts/AmmRebalancerProxyV1.json +5 -0
  184. package/dist/build/published_contracts/ChainlinkPriceOracleV1.json +1 -1
  185. package/dist/build/published_contracts/DolomiteAmmFactory.json +1 -1
  186. package/dist/build/published_contracts/DolomiteAmmRouterProxy.json +1 -1
  187. package/dist/build/published_contracts/DoubleExponentInterestSetter.json +2 -2
  188. package/dist/build/published_contracts/Expiry.json +1 -1
  189. package/dist/build/published_contracts/LiquidatorProxyV1.json +1 -1
  190. package/dist/build/published_contracts/LiquidatorProxyV1WithAmm.json +1 -1
  191. package/dist/build/published_contracts/MultiCall.json +1 -1
  192. package/dist/build/published_contracts/PayableProxy.json +2 -2
  193. package/dist/build/published_contracts/SignedOperationProxy.json +2 -2
  194. package/dist/build/published_contracts/SimpleFeeOwner.json +1 -1
  195. package/dist/build/published_contracts/TestUniswapAmmRebalancerProxy.json +140 -0
  196. package/dist/build/published_contracts/TransferProxy.json +1 -1
  197. package/dist/src/lib/Contracts.d.ts +3 -1
  198. package/dist/src/lib/Contracts.js +7 -3
  199. package/dist/src/lib/Contracts.js.map +1 -1
  200. package/package.json +2 -1
@@ -0,0 +1,465 @@
1
+ /*
2
+
3
+ Copyright 2021 Dolomite.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+
17
+ */
18
+
19
+ pragma solidity ^0.5.7;
20
+ pragma experimental ABIEncoderV2;
21
+
22
+ import "@openzeppelin/contracts/math/SafeMath.sol";
23
+ import "@openzeppelin/contracts/ownership/Ownable.sol";
24
+ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
25
+ import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
26
+ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
27
+
28
+ import "@uniswap/lib/contracts/libraries/Babylonian.sol";
29
+
30
+ import "../../protocol/interfaces/IExchangeWrapper.sol";
31
+ import "../../protocol/interfaces/IDolomiteMargin.sol";
32
+
33
+ import "../../protocol/lib/Account.sol";
34
+ import "../../protocol/lib/Actions.sol";
35
+ import "../../protocol/lib/Require.sol";
36
+ import "../../protocol/lib/Types.sol";
37
+
38
+ import "../lib/DolomiteAmmLibrary.sol";
39
+ import "../lib/TypedSignature.sol";
40
+
41
+ import "../interfaces/IDolomiteAmmFactory.sol";
42
+ import "../interfaces/IDolomiteAmmPair.sol";
43
+ import "../interfaces/IUniswapV2Router.sol";
44
+
45
+ import "../helpers/OnlyDolomiteMargin.sol";
46
+
47
+
48
+ /**
49
+ * @title AmmRebalancerProxyV1
50
+ * @author Dolomite
51
+ *
52
+ * Contract for re-balancing the Dolomite AMM pools against other UniswapV2Router compatible pools
53
+ */
54
+ contract AmmRebalancerProxyV1 is IExchangeWrapper, OnlyDolomiteMargin, Ownable {
55
+ using SafeERC20 for IERC20;
56
+ using SafeMath for uint;
57
+
58
+ bytes32 public constant FILE = "AmmRebalancerProxyV1";
59
+
60
+ address public DOLOMITE_AMM_FACTORY;
61
+ mapping(address => bytes32) public ROUTER_TO_INIT_CODE_HASH_MAP;
62
+
63
+ struct RebalanceParams {
64
+ bytes dolomitePath;
65
+ uint truePriceTokenA;
66
+ uint truePriceTokenB;
67
+ address otherRouter;
68
+ bytes otherPath;
69
+ }
70
+
71
+ struct RebalanceCache {
72
+ address dolomiteFactory;
73
+ address[] dolomitePools;
74
+ }
75
+
76
+ event RouterInitCodeHashSet(address indexed router, bytes32 initCodeHash);
77
+
78
+ // ============ Constructor ============
79
+
80
+ constructor (
81
+ address dolomiteMargin,
82
+ address dolomiteAmmFactory,
83
+ address[] memory routers,
84
+ bytes32[] memory initCodeHashes
85
+ )
86
+ public
87
+ OnlyDolomiteMargin(dolomiteMargin)
88
+ {
89
+ DOLOMITE_AMM_FACTORY = dolomiteAmmFactory;
90
+
91
+ Require.that(
92
+ routers.length == initCodeHashes.length,
93
+ FILE,
94
+ "routers/initCodes invalid length"
95
+ );
96
+ for (uint i = 0; i < routers.length; i++) {
97
+ ROUTER_TO_INIT_CODE_HASH_MAP[routers[i]] = initCodeHashes[i];
98
+ emit RouterInitCodeHashSet(routers[i], initCodeHashes[i]);
99
+ }
100
+ }
101
+
102
+ function adminSetRouterInitCodeHashes(
103
+ address[] calldata routers,
104
+ bytes32[] calldata initCodeHashes
105
+ )
106
+ external
107
+ onlyOwner {
108
+ Require.that(
109
+ routers.length == initCodeHashes.length,
110
+ FILE,
111
+ "routers/initCodes invalid length"
112
+ );
113
+
114
+ for (uint i = 0; i < routers.length; i++) {
115
+ ROUTER_TO_INIT_CODE_HASH_MAP[routers[i]] = initCodeHashes[i];
116
+ emit RouterInitCodeHashSet(routers[i], initCodeHashes[i]);
117
+ }
118
+ }
119
+
120
+ function exchange(
121
+ address,
122
+ address receiver,
123
+ address makerToken,
124
+ address takerToken,
125
+ uint256 requestedFillAmount,
126
+ bytes calldata orderData
127
+ )
128
+ external
129
+ onlyDolomiteMargin(msg.sender)
130
+ returns (uint256) {
131
+ (address router, uint amountOutMin, bytes memory rawPath) = abi.decode(orderData, (address, uint, bytes));
132
+ address[] memory path = _decodeRawPath(rawPath);
133
+ Require.that(
134
+ path[0] == takerToken,
135
+ FILE,
136
+ "path[0] not takerToken"
137
+ );
138
+ Require.that(
139
+ path[path.length - 1] == makerToken,
140
+ FILE,
141
+ "path[last] not makerToken"
142
+ );
143
+
144
+ _checkAllowanceAndApprove(takerToken, router, requestedFillAmount);
145
+
146
+ uint[] memory amounts = IUniswapV2Router(router).swapExactTokensForTokens(
147
+ requestedFillAmount,
148
+ amountOutMin,
149
+ path,
150
+ address(this),
151
+ block.timestamp
152
+ );
153
+
154
+ _checkAllowanceAndApprove(makerToken, receiver, amounts[amounts.length - 1]);
155
+
156
+ return amounts[amounts.length - 1];
157
+ }
158
+
159
+ function getExchangeCost(
160
+ address makerToken,
161
+ address takerToken,
162
+ uint256 desiredMakerToken,
163
+ bytes calldata orderData
164
+ )
165
+ external
166
+ view
167
+ returns (uint256) {
168
+ (address router,, bytes memory rawPath) = abi.decode(orderData, (address, uint, bytes));
169
+ address[] memory path = _decodeRawPath(rawPath);
170
+ Require.that(
171
+ path[0] == takerToken,
172
+ FILE,
173
+ "path[0] not takerToken"
174
+ );
175
+ Require.that(
176
+ path[path.length - 1] == makerToken,
177
+ FILE,
178
+ "path[last] not makerToken"
179
+ );
180
+
181
+ return IUniswapV2Router(router).getAmountsIn(desiredMakerToken, path)[0];
182
+ }
183
+
184
+ function performRebalance(
185
+ RebalanceParams memory params
186
+ ) public {
187
+ Require.that(
188
+ params.dolomitePath.length == 40 && params.otherPath.length >= 40 && params.otherPath.length % 20 == 0,
189
+ FILE,
190
+ "invalid path lengths"
191
+ );
192
+
193
+ address[] memory dolomitePath = _decodeRawPath(params.dolomitePath);
194
+ address[] memory otherPath = _decodeRawPath(params.otherPath);
195
+ Require.that(
196
+ dolomitePath[0] == otherPath[otherPath.length - 1] && dolomitePath[dolomitePath.length - 1] == otherPath[0],
197
+ FILE,
198
+ "invalid path alignment"
199
+ );
200
+
201
+ // solium-disable indentation
202
+ RebalanceCache memory cache;
203
+ {
204
+ address dolomiteFactory = DOLOMITE_AMM_FACTORY;
205
+ cache = RebalanceCache({
206
+ dolomiteFactory: dolomiteFactory,
207
+ dolomitePools: DolomiteAmmLibrary.getPools(dolomiteFactory, dolomitePath)
208
+ });
209
+ }
210
+ // solium-enable indentation
211
+
212
+ uint dolomiteAmountIn;
213
+ // solium-disable indentation
214
+ {
215
+ (uint256 reserveA, uint256 reserveB) = DolomiteAmmLibrary.getReservesWei(
216
+ cache.dolomiteFactory,
217
+ dolomitePath[0],
218
+ dolomitePath[1]
219
+ );
220
+ (bool isAToB, uint _dolomiteAmountIn) = _computeProfitMaximizingTrade(
221
+ params.truePriceTokenA,
222
+ params.truePriceTokenB,
223
+ reserveA,
224
+ reserveB
225
+ );
226
+
227
+ Require.that(
228
+ isAToB,
229
+ FILE,
230
+ "invalid aToB"
231
+ );
232
+
233
+ dolomiteAmountIn = _dolomiteAmountIn;
234
+ }
235
+ // solium-enable indentation
236
+
237
+ Account.Info[] memory accounts = new Account.Info[](2 + cache.dolomitePools.length);
238
+ accounts[0] = Account.Info({
239
+ owner : msg.sender,
240
+ number : 0
241
+ });
242
+ accounts[1] = Account.Info({
243
+ owner : msg.sender,
244
+ number : 1
245
+ });
246
+
247
+ for (uint i = 0; i < cache.dolomitePools.length; i++) {
248
+ accounts[2 + i] = Account.Info({
249
+ owner : cache.dolomitePools[i],
250
+ number : 0
251
+ });
252
+ }
253
+
254
+ uint[] memory dolomiteMarketPath = _getMarketPathFromTokenPath(dolomitePath);
255
+
256
+ // solium-disable indentation
257
+ uint otherAmountIn;
258
+ {
259
+ // blocked off to prevent the "stack too deep" error
260
+ bytes32 otherInitCodeHash = ROUTER_TO_INIT_CODE_HASH_MAP[params.otherRouter];
261
+ Require.that(
262
+ otherInitCodeHash != bytes32(0),
263
+ FILE,
264
+ "router not recognized"
265
+ );
266
+
267
+ // dolomiteAmountIn is the amountOut for the other trade
268
+ // Require.that(false, FILE, "printing results", dolomiteAmountIn);
269
+ otherAmountIn = DolomiteAmmLibrary.getAmountsIn(
270
+ IUniswapV2Router(params.otherRouter).factory(),
271
+ otherInitCodeHash,
272
+ dolomiteAmountIn,
273
+ otherPath
274
+ )[0];
275
+ }
276
+ // solium-enable indentation
277
+
278
+ // 1 action for transferring, 1 for selling via the other router, and trades are paths.length - 1
279
+ Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](2 + dolomitePath.length - 1);
280
+
281
+ // trade from accountIndex=1 and transfer to 0, to ensure re-balances are down with flash-loaned funds
282
+ // the dolomiteInputMarketId is the output market for the other trade and vice versa
283
+ // solium-disable indentation
284
+ {
285
+ // done to prevent the "stack too deep" error
286
+ uint otherAmountOut = dolomiteAmountIn;
287
+ actions[0] = _encodeSell(
288
+ 1,
289
+ dolomiteMarketPath[dolomiteMarketPath.length - 1],
290
+ dolomiteMarketPath[0],
291
+ otherAmountIn,
292
+ params.otherRouter,
293
+ params.otherPath,
294
+ otherAmountOut // this is the other trade's output amount
295
+ );
296
+ }
297
+ // solium-enable indentation
298
+
299
+ uint[] memory dolomiteAmountsOut = DolomiteAmmLibrary.getAmountsOutWei(
300
+ cache.dolomiteFactory,
301
+ dolomiteAmountIn,
302
+ dolomitePath
303
+ );
304
+ Require.that(
305
+ otherAmountIn <= dolomiteAmountsOut[dolomiteAmountsOut.length - 1],
306
+ FILE,
307
+ "arb closed"
308
+ );
309
+
310
+ for (uint i = 0; i < cache.dolomitePools.length; i++) {
311
+ Require.that(
312
+ accounts[i + 2].owner == cache.dolomitePools[i],
313
+ FILE,
314
+ "invalid pool owner address"
315
+ );
316
+ actions[i + 1] = _encodeTrade(
317
+ 1,
318
+ i + 2,
319
+ dolomiteMarketPath[i],
320
+ dolomiteMarketPath[i + 1],
321
+ cache.dolomitePools[i],
322
+ dolomiteAmountsOut[i],
323
+ dolomiteAmountsOut[i + 1]
324
+ );
325
+ }
326
+ actions[actions.length - 1] = _encodeTransferAll(
327
+ 1,
328
+ 0,
329
+ dolomiteMarketPath[dolomiteMarketPath.length - 1]
330
+ );
331
+
332
+ DOLOMITE_MARGIN.operate(accounts, actions);
333
+ }
334
+
335
+ // ============ Internal Functions ============
336
+
337
+ function _computeProfitMaximizingTrade(
338
+ uint256 truePriceTokenA,
339
+ uint256 truePriceTokenB,
340
+ uint256 reserveA,
341
+ uint256 reserveB
342
+ )
343
+ internal
344
+ pure
345
+ returns (bool isAToB, uint256 amountIn)
346
+ {
347
+ isAToB = reserveA.mul(truePriceTokenB).div(reserveB) < truePriceTokenA;
348
+
349
+ uint256 invariant = reserveA.mul(reserveB);
350
+
351
+ uint256 leftSide = Babylonian.sqrt(
352
+ invariant.mul(isAToB ? truePriceTokenA : truePriceTokenB).mul(1000) /
353
+ uint256(isAToB ? truePriceTokenB : truePriceTokenA).mul(997)
354
+ );
355
+ uint256 rightSide = (isAToB ? reserveA.mul(1000) : reserveB.mul(1000)) / 997;
356
+
357
+ // compute the amount that must be sent to move the price to the profit-maximizing price
358
+ amountIn = leftSide.sub(rightSide);
359
+ }
360
+
361
+ function _decodeRawPath(
362
+ bytes memory rawPath
363
+ ) internal pure returns (address[] memory) {
364
+ Require.that(
365
+ rawPath.length % 20 == 0 && rawPath.length >= 40,
366
+ FILE,
367
+ "invalid path length"
368
+ );
369
+ address[] memory path = new address[](rawPath.length / 20);
370
+ for (uint i = 0; i < path.length; i++) {
371
+ uint offset = 20 * i; // 20 bytes per address
372
+ bytes20 token;
373
+ // solium-disable-next-line
374
+ assembly {
375
+ token := mload(add(add(rawPath, 32), offset))
376
+ }
377
+ path[i] = address(token);
378
+ }
379
+ return path;
380
+ }
381
+
382
+ function _checkAllowanceAndApprove(
383
+ address token,
384
+ address spender,
385
+ uint amount
386
+ ) internal {
387
+ if (IERC20(token).allowance(address(this), spender) < amount) {
388
+ IERC20(token).safeApprove(spender, uint(- 1));
389
+ }
390
+ }
391
+
392
+ function _encodeSell(
393
+ uint fromAccountIndex,
394
+ uint primaryMarketId,
395
+ uint secondaryMarketId,
396
+ uint amountInWei,
397
+ address router,
398
+ bytes memory path,
399
+ uint amountOutWei
400
+ ) internal view returns (Actions.ActionArgs memory) {
401
+ return Actions.ActionArgs({
402
+ actionType : Actions.ActionType.Sell,
403
+ accountId : fromAccountIndex,
404
+ // solium-disable-next-line arg-overflow
405
+ amount : Types.AssetAmount(false, Types.AssetDenomination.Wei, Types.AssetReference.Delta, amountInWei),
406
+ primaryMarketId : primaryMarketId,
407
+ secondaryMarketId : secondaryMarketId,
408
+ otherAddress : address(this),
409
+ otherAccountId : uint(- 1),
410
+ data : abi.encode(router, amountOutWei, path)
411
+ });
412
+ }
413
+
414
+ function _encodeTrade(
415
+ uint fromAccountIndex,
416
+ uint toAccountIndex,
417
+ uint primaryMarketId,
418
+ uint secondaryMarketId,
419
+ address traderAddress,
420
+ uint amountInWei,
421
+ uint amountOutWei
422
+ ) internal pure returns (Actions.ActionArgs memory) {
423
+ return Actions.ActionArgs({
424
+ actionType : Actions.ActionType.Trade,
425
+ accountId : fromAccountIndex,
426
+ // solium-disable-next-line arg-overflow
427
+ amount : Types.AssetAmount(true, Types.AssetDenomination.Wei, Types.AssetReference.Delta, amountInWei),
428
+ primaryMarketId : primaryMarketId,
429
+ secondaryMarketId : secondaryMarketId,
430
+ otherAddress : traderAddress,
431
+ otherAccountId : toAccountIndex,
432
+ data : abi.encode(amountOutWei)
433
+ });
434
+ }
435
+
436
+ function _encodeTransferAll(
437
+ uint fromAccountIndex,
438
+ uint toAccountIndex,
439
+ uint marketId
440
+ ) internal pure returns (Actions.ActionArgs memory) {
441
+ return Actions.ActionArgs({
442
+ actionType : Actions.ActionType.Transfer,
443
+ accountId : fromAccountIndex,
444
+ // solium-disable-next-line arg-overflow
445
+ amount : Types.AssetAmount(true, Types.AssetDenomination.Wei, Types.AssetReference.Target, 0),
446
+ primaryMarketId : marketId,
447
+ secondaryMarketId : uint(- 1),
448
+ otherAddress : address(0),
449
+ otherAccountId : toAccountIndex,
450
+ data : bytes("")
451
+ });
452
+ }
453
+
454
+ function _getMarketPathFromTokenPath(
455
+ address[] memory path
456
+ ) internal view returns (uint[] memory) {
457
+ IDolomiteMargin dolomiteMargin = DOLOMITE_MARGIN;
458
+ uint[] memory marketPath = new uint[](path.length);
459
+ for (uint i = 0; i < path.length; i++) {
460
+ marketPath[i] = dolomiteMargin.getMarketIdByTokenAddress(path[i]);
461
+ }
462
+ return marketPath;
463
+ }
464
+
465
+ }