@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,573 @@
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.16;
20
+ pragma experimental ABIEncoderV2;
21
+
22
+ import "../../protocol/interfaces/IAutoTrader.sol";
23
+ import "../../protocol/interfaces/IDolomiteMargin.sol";
24
+ import "../../protocol/lib/Math.sol";
25
+ import "../../protocol/lib/Require.sol";
26
+
27
+ import "../interfaces/IDolomiteAmmFactory.sol";
28
+ import "../interfaces/IDolomiteAmmPair.sol";
29
+
30
+ import "../lib/AdvancedMath.sol";
31
+ import "../lib/UQ112x112.sol";
32
+
33
+ import "../interfaces/ITransferProxy.sol";
34
+
35
+ import "./DolomiteAmmERC20.sol";
36
+
37
+
38
+ contract DolomiteAmmPair is IDolomiteAmmPair, DolomiteAmmERC20, IAutoTrader {
39
+ using Math for uint;
40
+ using SafeMath for uint;
41
+ using UQ112x112 for uint224;
42
+
43
+ bytes32 internal constant FILE = "DolomiteAmmPair";
44
+
45
+ uint public constant INDEX_BASE = 1e18;
46
+ uint public constant MINIMUM_LIQUIDITY = 10 ** 3;
47
+
48
+ address public factory;
49
+ address public dolomiteMargin;
50
+ address public dolomiteMarginTransferProxy;
51
+ address public token0;
52
+ address public token1;
53
+
54
+ uint112 private reserve0Par; // uses single storage slot, accessible via getReserves
55
+ uint112 private reserve1Par; // uses single storage slot, accessible via getReserves
56
+ uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves
57
+
58
+ uint128 public marketId0;
59
+ uint128 public marketId1;
60
+
61
+ uint public price0CumulativeLast;
62
+ uint public price1CumulativeLast;
63
+ uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
64
+
65
+ uint private unlocked = 1;
66
+ modifier lock() {
67
+ Require.that(
68
+ unlocked == 1,
69
+ FILE,
70
+ "locked"
71
+ );
72
+ unlocked = 0;
73
+ _;
74
+ unlocked = 1;
75
+ }
76
+
77
+ struct DolomiteAmmCache {
78
+ IDolomiteMargin dolomiteMargin;
79
+ uint marketId0;
80
+ uint marketId1;
81
+ uint balance0Wei;
82
+ uint balance1Wei;
83
+ Interest.Index index0;
84
+ Interest.Index index1;
85
+ }
86
+
87
+ constructor() public {
88
+ factory = msg.sender;
89
+ }
90
+
91
+ // called once by the factory at time of deployment
92
+ function initialize(address _token0, address _token1, address _transferProxy) external {
93
+ Require.that(
94
+ msg.sender == factory,
95
+ FILE,
96
+ "forbidden"
97
+ );
98
+ Require.that(
99
+ ITransferProxy(_transferProxy).isCallerTrusted(address(this)),
100
+ FILE,
101
+ "transfer proxy not enabled"
102
+ );
103
+ // sufficient check
104
+ token0 = _token0;
105
+ token1 = _token1;
106
+ dolomiteMargin = IDolomiteAmmFactory(msg.sender).dolomiteMargin();
107
+ dolomiteMarginTransferProxy = _transferProxy;
108
+
109
+ marketId0 = uint128(IDolomiteMargin(dolomiteMargin).getMarketIdByTokenAddress(token0));
110
+ marketId1 = uint128(IDolomiteMargin(dolomiteMargin).getMarketIdByTokenAddress(token1));
111
+ }
112
+
113
+ // this low-level function should be called from a contract which performs important safety checks
114
+ function mint(address to) external lock returns (uint liquidity) {
115
+ (uint112 _reserve0, uint112 _reserve1,) = getReservesPar();
116
+ // gas savings
117
+ IDolomiteMargin _dolomiteMargin = IDolomiteMargin(dolomiteMargin);
118
+ uint balance0 = _getTokenBalancePar(_dolomiteMargin, marketId0);
119
+ uint balance1 = _getTokenBalancePar(_dolomiteMargin, marketId1);
120
+ uint amount0 = balance0.sub(_reserve0);
121
+ uint amount1 = balance1.sub(_reserve1);
122
+
123
+ Require.that(
124
+ amount0 > 0,
125
+ FILE,
126
+ "invalid mint amount 0"
127
+ );
128
+ Require.that(
129
+ amount1 > 0,
130
+ FILE,
131
+ "invalid mint amount 1"
132
+ );
133
+
134
+ bool feeOn = _mintFee(_reserve0, _reserve1);
135
+ uint _totalSupply = totalSupply;
136
+ // gas savings, must be defined here since totalSupply can update in _mintFee
137
+ if (_totalSupply == 0) {
138
+ liquidity = AdvancedMath.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
139
+ // permanently lock the first MINIMUM_LIQUIDITY tokens
140
+ _mint(address(0), MINIMUM_LIQUIDITY);
141
+ } else {
142
+ liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
143
+ }
144
+
145
+ Require.that(
146
+ liquidity > 0,
147
+ FILE,
148
+ "insufficient liquidity minted"
149
+ );
150
+
151
+ _mint(to, liquidity);
152
+
153
+ _update(
154
+ balance0,
155
+ balance1,
156
+ _reserve0,
157
+ _reserve1
158
+ );
159
+ if (feeOn) kLast = uint(reserve0Par).mul(reserve1Par);
160
+ // reserve0 and reserve1 are up-to-date
161
+ emit Mint(msg.sender, amount0, amount1);
162
+ }
163
+
164
+ // this low-level function should be called from a contract which performs important safety checks
165
+ function burn(address to, uint toAccountNumber) external lock returns (uint amount0Wei, uint amount1Wei) {
166
+ (uint112 _reserve0, uint112 _reserve1,) = getReservesPar();
167
+ // gas savings
168
+ IDolomiteMargin _dolomiteMargin = IDolomiteMargin(dolomiteMargin);
169
+ uint[] memory markets = new uint[](2);
170
+ markets[0] = marketId0;
171
+ markets[1] = marketId1;
172
+
173
+ // gas savings
174
+ uint balance0 = _getTokenBalancePar(_dolomiteMargin, markets[0]);
175
+ uint balance1 = _getTokenBalancePar(_dolomiteMargin, markets[1]);
176
+
177
+ bool feeOn;
178
+ /* solium-disable indentation */
179
+ {
180
+ // new scope to prevent stack-too-deep issues
181
+ uint liquidity = balanceOf[address(this)];
182
+
183
+ uint token0Index = _dolomiteMargin.getMarketCurrentIndex(markets[0]).supply;
184
+ uint token1Index = _dolomiteMargin.getMarketCurrentIndex(markets[1]).supply;
185
+
186
+ feeOn = _mintFee(_reserve0, _reserve1);
187
+ uint _totalSupply = totalSupply;
188
+ // gas savings, must be defined here since totalSupply can update in _mintFee
189
+ amount0Wei = (liquidity.mul(balance0) / _totalSupply).getPartialRoundHalfUp(token0Index, INDEX_BASE);
190
+ // using balances ensures pro-rata distribution
191
+ amount1Wei = (liquidity.mul(balance1) / _totalSupply).getPartialRoundHalfUp(token1Index, INDEX_BASE);
192
+ Require.that(
193
+ amount0Wei > 0 && amount1Wei > 0,
194
+ FILE,
195
+ "insufficient liquidity burned"
196
+ );
197
+
198
+ _burn(address(this), liquidity);
199
+ }
200
+ /* solium-enable indentation */
201
+
202
+ uint[] memory amounts = new uint[](2);
203
+ amounts[0] = amount0Wei;
204
+ amounts[1] = amount1Wei;
205
+
206
+ ITransferProxy(dolomiteMarginTransferProxy).transferMultipleWithMarkets(
207
+ 0,
208
+ to,
209
+ toAccountNumber,
210
+ markets,
211
+ amounts
212
+ );
213
+
214
+ balance0 = _getTokenBalancePar(_dolomiteMargin, markets[0]);
215
+ balance1 = _getTokenBalancePar(_dolomiteMargin, markets[1]);
216
+
217
+ _update(
218
+ balance0,
219
+ balance1,
220
+ _reserve0,
221
+ _reserve1
222
+ );
223
+ if (feeOn) kLast = uint(reserve0Par).mul(reserve1Par);
224
+
225
+ // reserve0 and reserve1 are up-to-date
226
+ emit Burn(
227
+ msg.sender,
228
+ amount0Wei,
229
+ amount1Wei, to
230
+ );
231
+ }
232
+
233
+ // force balances to match reserves
234
+ function skim(address to, uint toAccountNumber) external lock {
235
+ // gas savings
236
+ IDolomiteMargin _dolomiteMargin = IDolomiteMargin(dolomiteMargin);
237
+
238
+ uint[] memory markets = new uint[](2);
239
+ markets[0] = marketId0;
240
+ markets[1] = marketId1;
241
+
242
+ uint amount0 = _getTokenBalancePar(_dolomiteMargin, markets[0]).sub(reserve0Par);
243
+ uint amount1 = _getTokenBalancePar(_dolomiteMargin, markets[1]).sub(reserve1Par);
244
+
245
+ uint[] memory amounts = new uint[](2);
246
+ amounts[0] = amount0;
247
+ amounts[1] = amount1;
248
+
249
+ ITransferProxy(dolomiteMarginTransferProxy).transferMultipleWithMarkets(
250
+ 0,
251
+ to,
252
+ toAccountNumber,
253
+ markets,
254
+ amounts
255
+ );
256
+ }
257
+
258
+ // force reserves to match balances
259
+ function sync() external lock {
260
+ IDolomiteMargin _dolomiteMargin = IDolomiteMargin(dolomiteMargin);
261
+ _update(
262
+ _getTokenBalancePar(_dolomiteMargin, marketId0),
263
+ _getTokenBalancePar(_dolomiteMargin, marketId1),
264
+ reserve0Par,
265
+ reserve1Par
266
+ );
267
+ }
268
+
269
+ function token0Symbol() public view returns (string memory) {
270
+ address _token0 = token0;
271
+ return _callOptionalReturn(_token0, abi.encodePacked(IERC20Detailed(_token0).symbol.selector));
272
+ }
273
+
274
+ function token1Symbol() public view returns (string memory) {
275
+ address _token1 = token1;
276
+ return _callOptionalReturn(_token1, abi.encodePacked(IERC20Detailed(_token1).symbol.selector));
277
+ }
278
+
279
+ function name() public view returns (string memory) {
280
+ /* solium-disable-next-line arg-overflow */
281
+ return string(abi.encodePacked("Dolomite LP Token: ", token0Symbol(), "_", token1Symbol()));
282
+ }
283
+
284
+ function symbol() public view returns (string memory) {
285
+ /* solium-disable-next-line arg-overflow */
286
+ return string(abi.encodePacked("DLP_", token0Symbol(), "_", token1Symbol()));
287
+ }
288
+
289
+ function decimals() public pure returns (uint8) {
290
+ return 18;
291
+ }
292
+
293
+ function getReservesPar() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
294
+ _reserve0 = reserve0Par;
295
+ _reserve1 = reserve1Par;
296
+ _blockTimestampLast = blockTimestampLast;
297
+ }
298
+
299
+ function getReservesWei() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
300
+ IDolomiteMargin _dolomiteMargin = IDolomiteMargin(dolomiteMargin);
301
+
302
+ uint reserve0InterestIndex = _dolomiteMargin.getMarketCurrentIndex(marketId0).supply;
303
+ uint reserve1InterestIndex = _dolomiteMargin.getMarketCurrentIndex(marketId1).supply;
304
+
305
+ _reserve0 = uint112(uint(reserve0Par).getPartialRoundHalfUp(reserve0InterestIndex, INDEX_BASE));
306
+ _reserve1 = uint112(uint(reserve1Par).getPartialRoundHalfUp(reserve1InterestIndex, INDEX_BASE));
307
+ _blockTimestampLast = blockTimestampLast;
308
+ }
309
+
310
+ function getTradeCost(
311
+ uint256 inputMarketId,
312
+ uint256 outputMarketId,
313
+ Account.Info memory makerAccount,
314
+ Account.Info memory takerAccount,
315
+ Types.Par memory,
316
+ Types.Par memory,
317
+ Types.Wei memory inputWei,
318
+ bytes memory data
319
+ )
320
+ public
321
+ returns (Types.AssetAmount memory) {
322
+ DolomiteAmmCache memory cache;
323
+ /* solium-disable indentation */
324
+ {
325
+ IDolomiteMargin _dolomiteMargin = IDolomiteMargin(dolomiteMargin);
326
+ cache = DolomiteAmmCache({
327
+ dolomiteMargin : _dolomiteMargin,
328
+ marketId0 : marketId0,
329
+ marketId1 : marketId1,
330
+ balance0Wei : _getTokenBalanceWei(_dolomiteMargin, marketId0),
331
+ balance1Wei : _getTokenBalanceWei(_dolomiteMargin, marketId1),
332
+ index0 : _dolomiteMargin.getMarketCurrentIndex(marketId0),
333
+ index1 : _dolomiteMargin.getMarketCurrentIndex(marketId1)
334
+ });
335
+ }
336
+ /* solium-enable indentation */
337
+
338
+ Require.that(
339
+ msg.sender == address(cache.dolomiteMargin),
340
+ FILE,
341
+ "invalid sender"
342
+ );
343
+ Require.that(
344
+ makerAccount.owner == address(this),
345
+ FILE,
346
+ "invalid maker account owner"
347
+ );
348
+ Require.that(
349
+ makerAccount.number == 0,
350
+ FILE,
351
+ "invalid maker account number"
352
+ );
353
+ Require.that(
354
+ token0 != takerAccount.owner && token1 != takerAccount.owner && address(this) != takerAccount.owner,
355
+ FILE,
356
+ "invalid taker account owner"
357
+ );
358
+
359
+ uint amount0OutWei;
360
+ uint amount1OutWei;
361
+ /* solium-disable indentation */
362
+ {
363
+ Require.that(
364
+ inputMarketId == cache.marketId0 || inputMarketId == cache.marketId1,
365
+ FILE,
366
+ "invalid input market"
367
+ );
368
+ Require.that(
369
+ outputMarketId == cache.marketId0 || outputMarketId == cache.marketId1,
370
+ FILE,
371
+ "invalid output market"
372
+ );
373
+ Require.that(
374
+ inputWei.sign,
375
+ FILE,
376
+ "input wei must be positive"
377
+ );
378
+
379
+ (uint amountOutWei) = abi.decode(data, ((uint)));
380
+
381
+ Require.that(
382
+ amountOutWei > 0,
383
+ FILE,
384
+ "insufficient output amount"
385
+ );
386
+
387
+ if (inputMarketId == cache.marketId0) {
388
+ cache.balance0Wei = cache.balance0Wei.add(inputWei.value);
389
+ cache.balance1Wei = cache.balance1Wei.sub(amountOutWei);
390
+
391
+ amount0OutWei = 0;
392
+ amount1OutWei = amountOutWei;
393
+ } else {
394
+ assert(inputMarketId == cache.marketId1);
395
+
396
+ cache.balance1Wei = cache.balance1Wei.add(inputWei.value);
397
+ cache.balance0Wei = cache.balance0Wei.sub(amountOutWei);
398
+
399
+ amount0OutWei = amountOutWei;
400
+ amount1OutWei = 0;
401
+ }
402
+ }
403
+ /* solium-enable indentation */
404
+
405
+ uint amount0InWei;
406
+ uint amount1InWei;
407
+ /* solium-disable indentation */
408
+ {
409
+ // gas savings
410
+ (uint112 _reserve0, uint112 _reserve1,) = getReservesWei();
411
+ Require.that(
412
+ amount0OutWei < _reserve0 && amount1OutWei < _reserve1,
413
+ FILE,
414
+ "insufficient liquidity"
415
+ );
416
+
417
+ amount0InWei = cache.balance0Wei > (_reserve0 - amount0OutWei)
418
+ ? cache.balance0Wei - (_reserve0 - amount0OutWei) : 0;
419
+
420
+ amount1InWei = cache.balance1Wei > (_reserve1 - amount1OutWei)
421
+ ? cache.balance1Wei - (_reserve1 - amount1OutWei) : 0;
422
+
423
+ Require.that(
424
+ amount0InWei > 0 || amount1InWei > 0,
425
+ FILE,
426
+ "insufficient input amount"
427
+ );
428
+
429
+ uint balance0Adjusted = cache.balance0Wei.mul(1000).sub(amount0InWei.mul(3));
430
+ uint balance1Adjusted = cache.balance1Wei.mul(1000).sub(amount1InWei.mul(3));
431
+ Require.that(
432
+ balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000 ** 2),
433
+ FILE,
434
+ "K"
435
+ );
436
+
437
+ // convert the numbers from wei to par
438
+ _update(
439
+ cache.balance0Wei.getPartialRoundHalfUp(INDEX_BASE, cache.index0.supply),
440
+ cache.balance1Wei.getPartialRoundHalfUp(INDEX_BASE, cache.index1.supply),
441
+ uint112(uint(_reserve0).getPartialRoundHalfUp(INDEX_BASE, cache.index0.supply)),
442
+ uint112(uint(_reserve1).getPartialRoundHalfUp(INDEX_BASE, cache.index1.supply))
443
+ );
444
+ }
445
+ /* solium-enable indentation */
446
+
447
+ emit Swap(
448
+ msg.sender,
449
+ amount0InWei,
450
+ amount1InWei,
451
+ amount0OutWei,
452
+ amount1OutWei,
453
+ takerAccount.owner
454
+ );
455
+
456
+ return Types.AssetAmount({
457
+ sign : false,
458
+ denomination : Types.AssetDenomination.Wei,
459
+ ref : Types.AssetReference.Delta,
460
+ value : amount0OutWei > 0 ? amount0OutWei : amount1OutWei
461
+ });
462
+ }
463
+
464
+ // ============ Internal Functions ============
465
+
466
+ function _callOptionalReturn(address token, bytes memory data) internal view returns (string memory) {
467
+ // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
468
+ // we're implementing it ourselves.
469
+
470
+ // A Solidity high level call has three parts:
471
+ // 1. The target address is checked to contain contract code. Not needed since tokens are manually added
472
+ // 2. The call itself is made, and success asserted
473
+ // 3. The return value is decoded, which in turn checks the size of the returned data.
474
+
475
+ // solhint-disable-next-line avoid-low-level-calls
476
+ (bool success, bytes memory returnData) = token.staticcall(data);
477
+
478
+ if (success && returnData.length > 0) {
479
+ // Return data is optional
480
+ return abi.decode(returnData, (string));
481
+ } else {
482
+ return "";
483
+ }
484
+ }
485
+
486
+ function _encodeTransferAction(
487
+ uint fromAccountIndex,
488
+ uint toAccountIndex,
489
+ uint marketId,
490
+ uint amount
491
+ ) internal pure returns (Actions.ActionArgs memory) {
492
+ return Actions.ActionArgs({
493
+ actionType : Actions.ActionType.Transfer,
494
+ accountId : fromAccountIndex,
495
+ /* solium-disable-next-line arg-overflow */
496
+ amount : Types.AssetAmount(false, Types.AssetDenomination.Par, Types.AssetReference.Delta, amount),
497
+ primaryMarketId : marketId,
498
+ secondaryMarketId : uint(- 1),
499
+ otherAddress : address(0),
500
+ otherAccountId : toAccountIndex,
501
+ data : bytes("")
502
+ });
503
+ }
504
+
505
+ /// @dev Updates reserves and, on the first call per block, price accumulators. THESE SHOULD ALL BE IN PAR
506
+ function _update(
507
+ uint balance0,
508
+ uint balance1,
509
+ uint112 reserve0,
510
+ uint112 reserve1
511
+ ) internal {
512
+ Require.that(
513
+ balance0 <= uint112(- 1) && balance1 <= uint112(- 1),
514
+ FILE,
515
+ "balance overflow"
516
+ );
517
+
518
+ uint32 blockTimestamp = uint32(block.timestamp % 2 ** 32);
519
+ uint32 timeElapsed = blockTimestamp - blockTimestampLast;
520
+ // overflow is desired
521
+ if (timeElapsed > 0 && reserve0 != 0 && reserve1 != 0) {
522
+ // * never overflows, and + overflow is desired
523
+ price0CumulativeLast += uint(UQ112x112.encode(reserve1).uqdiv(reserve0)) * timeElapsed;
524
+ price1CumulativeLast += uint(UQ112x112.encode(reserve0).uqdiv(reserve1)) * timeElapsed;
525
+ }
526
+ reserve0Par = uint112(balance0);
527
+ reserve1Par = uint112(balance1);
528
+ blockTimestampLast = blockTimestamp;
529
+ emit Sync(reserve0Par, reserve1Par);
530
+ }
531
+
532
+ // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
533
+ function _mintFee(
534
+ uint112 reserve0,
535
+ uint112 reserve1
536
+ ) internal returns (bool feeOn) {
537
+ address feeTo = IDolomiteAmmFactory(factory).feeTo();
538
+ // gas savings
539
+ feeOn = feeTo != address(0);
540
+ uint _kLast = kLast;
541
+ // gas savings
542
+ if (feeOn) {
543
+ if (_kLast != 0) {
544
+ uint rootK = AdvancedMath.sqrt(uint(reserve0).mul(reserve1));
545
+ uint rootKLast = AdvancedMath.sqrt(_kLast);
546
+ if (rootK > rootKLast) {
547
+ // Fee is 1/3 of the trading fee of 0.3%, which is 0.1% or 0.001
548
+ uint numerator = totalSupply.mul(rootK.sub(rootKLast));
549
+ uint denominator = rootK.mul(2).add(rootKLast);
550
+ uint liquidity = numerator / denominator;
551
+ if (liquidity > 0) _mint(feeTo, liquidity);
552
+ }
553
+ }
554
+ } else if (_kLast != 0) {
555
+ kLast = 0;
556
+ }
557
+ }
558
+
559
+ function _getTokenBalancePar(
560
+ IDolomiteMargin _dolomiteMargin,
561
+ uint marketId
562
+ ) internal view returns (uint) {
563
+ return _dolomiteMargin.getAccountPar(Account.Info(address(this), 0), marketId).value;
564
+ }
565
+
566
+ function _getTokenBalanceWei(
567
+ IDolomiteMargin _dolomiteMargin,
568
+ uint marketId
569
+ ) internal view returns (uint) {
570
+ return _dolomiteMargin.getAccountWei(Account.Info(address(this), 0), marketId).value;
571
+ }
572
+
573
+ }
@@ -0,0 +1,107 @@
1
+ pragma solidity ^0.5.16;
2
+ pragma experimental ABIEncoderV2;
3
+
4
+ import "@openzeppelin/contracts/ownership/Ownable.sol";
5
+ import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
6
+
7
+ import "../../protocol/interfaces/IDolomiteMargin.sol";
8
+ import "../../protocol/lib/Account.sol";
9
+ import "../../protocol/lib/Actions.sol";
10
+
11
+ import "../interfaces/IDolomiteAmmFactory.sol";
12
+ import "../interfaces/IDolomiteAmmPair.sol";
13
+
14
+
15
+ contract SimpleFeeOwner is Ownable {
16
+ using SafeERC20 for IERC20;
17
+
18
+ event OwnershipChanged(address indexed newOwner, address indexed oldOwner);
19
+
20
+ IDolomiteAmmFactory uniswapFactory;
21
+ IDolomiteMargin dolomiteMargin;
22
+
23
+ constructor(
24
+ address _uniswapFactory,
25
+ address _dolomiteMargin
26
+ ) public {
27
+ uniswapFactory = IDolomiteAmmFactory(_uniswapFactory);
28
+ dolomiteMargin = IDolomiteMargin(_dolomiteMargin);
29
+ }
30
+
31
+ function uniswapSetFeeTo(
32
+ address feeTo
33
+ )
34
+ external
35
+ onlyOwner {
36
+ uniswapFactory.setFeeTo(feeTo);
37
+ }
38
+
39
+ function uniswapSetFeeToSetter(
40
+ address feeToSetter
41
+ )
42
+ external
43
+ onlyOwner {
44
+ uniswapFactory.setFeeToSetter(feeToSetter);
45
+ }
46
+
47
+ function withdrawAllFeesByTokens(
48
+ address recipient,
49
+ address[] calldata tokens
50
+ )
51
+ external
52
+ onlyOwner {
53
+ for (uint i = 0; i < tokens.length; i++) {
54
+ address token = tokens[i];
55
+ uint amount = IERC20(token).balanceOf(address(this));
56
+ IERC20(token).safeTransfer(recipient, amount);
57
+ }
58
+ }
59
+
60
+ function unwrapAllFeesByLpTokens(
61
+ address recipient,
62
+ address[] calldata lpTokens
63
+ )
64
+ external
65
+ onlyOwner {
66
+ for (uint i = 0; i < lpTokens.length; i++) {
67
+ IDolomiteAmmPair lpToken = IDolomiteAmmPair(lpTokens[i]);
68
+ lpToken.transfer(address(lpToken), lpToken.balanceOf(address(this)));
69
+ lpToken.burn(address(this), 0);
70
+
71
+ address token0 = lpToken.token0();
72
+ address token1 = lpToken.token1();
73
+
74
+ uint marketId0 = dolomiteMargin.getMarketIdByTokenAddress(token0);
75
+ uint marketId1 = dolomiteMargin.getMarketIdByTokenAddress(token1);
76
+
77
+ Account.Info[] memory accounts = new Account.Info[](1);
78
+ accounts[0] = Account.Info(address(this), 0);
79
+
80
+ Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](2);
81
+ actions[0] = _encodeWithdrawAllToThisContract(marketId0);
82
+ actions[1] = _encodeWithdrawAllToThisContract(marketId1);
83
+
84
+ dolomiteMargin.operate(accounts, actions);
85
+
86
+ IERC20(token0).safeTransfer(recipient, IERC20(token0).balanceOf(address(this)));
87
+ IERC20(token1).safeTransfer(recipient, IERC20(token1).balanceOf(address(this)));
88
+ }
89
+ }
90
+
91
+ function _encodeWithdrawAllToThisContract(
92
+ uint marketId
93
+ ) internal view returns (Actions.ActionArgs memory) {
94
+ return Actions.ActionArgs({
95
+ actionType : Actions.ActionType.Withdraw,
96
+ accountId : 0,
97
+ /* solium-disable-next-line arg-overflow */
98
+ amount : Types.AssetAmount(true, Types.AssetDenomination.Wei, Types.AssetReference.Target, 0),
99
+ primaryMarketId : marketId,
100
+ secondaryMarketId : uint(- 1),
101
+ otherAddress : address(this),
102
+ otherAccountId : uint(- 1),
103
+ data : bytes("")
104
+ });
105
+ }
106
+
107
+ }