@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.
- package/build/contracts/Account.json +11 -11
- package/build/contracts/Actions.json +11 -11
- package/build/contracts/Address.json +1 -1
- package/build/contracts/Admin.json +23 -23
- package/build/contracts/AdminImpl.json +35 -307
- package/build/contracts/AdvancedMath.json +7 -7
- package/build/contracts/AmmRebalancerProxy.json +577 -621
- package/build/contracts/AmmRebalancerProxyV1.json +78 -32
- package/build/contracts/Babylonian.json +1 -1
- package/build/contracts/Bits.json +9 -9
- package/build/contracts/Cache.json +13 -13
- package/build/contracts/ChainlinkPriceOracleV1.json +16 -16
- package/build/contracts/Context.json +1 -1
- package/build/contracts/CustomTestToken.json +9 -9
- package/build/contracts/Decimal.json +9 -9
- package/build/contracts/DelayedMultiSig.json +9 -9
- package/build/contracts/DolomiteAmmERC20.json +11 -11
- package/build/contracts/DolomiteAmmFactory.json +14 -52
- package/build/contracts/DolomiteAmmLibrary.json +24 -24
- package/build/contracts/DolomiteAmmPair.json +27 -27
- package/build/contracts/DolomiteAmmRouterProxy.json +30 -363
- package/build/contracts/DolomiteMargin.json +21 -67
- package/build/contracts/DoubleExponentInterestSetter.json +15 -21
- package/build/contracts/EnumerableSet.json +7 -7
- package/build/contracts/ErroringOmiseToken.json +9 -9
- package/build/contracts/ErroringToken.json +10 -10
- package/build/contracts/Events.json +17 -17
- package/build/contracts/ExcessivelySafeCall.json +35 -35
- package/build/contracts/Exchange.json +15 -15
- package/build/contracts/Expiry.json +36 -36
- package/build/contracts/Getters.json +33 -33
- package/build/contracts/IAutoTrader.json +9 -9
- package/build/contracts/ICallee.json +7 -7
- package/build/contracts/IChainlinkAggregator.json +5 -5
- package/build/contracts/IDolomiteAmmERC20.json +5 -5
- package/build/contracts/IDolomiteAmmFactory.json +9 -9
- package/build/contracts/IDolomiteAmmPair.json +9 -9
- package/build/contracts/IDolomiteMargin.json +23 -23
- package/build/contracts/IERC20.json +1 -1
- package/build/contracts/IERC20Detailed.json +5 -5
- package/build/contracts/IExchangeWrapper.json +5 -5
- package/build/contracts/IExpiry.json +9 -9
- package/build/contracts/IInterestSetter.json +7 -7
- package/build/contracts/ILiquidationCallback.json +7 -7
- package/build/contracts/IMakerOracle.json +5 -5
- package/build/contracts/IOasisDex.json +5 -5
- package/build/contracts/IPriceOracle.json +7 -7
- package/build/contracts/IRecyclable.json +9 -9
- package/build/contracts/ITransferProxy.json +5 -5
- package/build/contracts/IUniswapV2Callee.json +5 -5
- package/build/contracts/IUniswapV2Factory.json +5 -5
- package/build/contracts/IUniswapV2Pair.json +5 -5
- package/build/contracts/IUniswapV2Router.json +5 -5
- package/build/contracts/IWETH.json +5 -5
- package/build/contracts/Interest.json +15 -15
- package/build/contracts/LiquidateOrVaporizeImpl.json +32 -83
- package/build/contracts/LiquidatorProxyHelper.json +23 -23
- package/build/contracts/LiquidatorProxyV1.json +30 -36
- package/build/contracts/LiquidatorProxyV1WithAmm.json +49 -105
- package/build/contracts/Math.json +1 -1
- package/build/contracts/Migrations.json +8 -14
- package/build/contracts/Monetary.json +7 -7
- package/build/contracts/MultiCall.json +8 -14
- package/build/contracts/MultiSig.json +7 -7
- package/build/contracts/OmiseToken.json +8 -8
- package/build/contracts/OnlyDolomiteMargin.json +11 -11
- package/build/contracts/Operation.json +15 -15
- package/build/contracts/OperationImpl.json +39 -47
- package/build/contracts/Ownable.json +1 -1
- package/build/contracts/PartiallyDelayedMultiSig.json +9 -9
- package/build/contracts/PayableProxy.json +17 -23
- package/build/contracts/Permission.json +11 -11
- package/build/contracts/PolynomialInterestSetter.json +13 -13
- package/build/contracts/RecyclableTokenProxy.json +25 -25
- package/build/contracts/ReentrancyGuard.json +1 -1
- package/build/contracts/Require.json +7 -7
- package/build/contracts/SafeERC20.json +1 -1
- package/build/contracts/SafeETH.json +7 -7
- package/build/contracts/SafeLiquidationCallback.json +17 -17
- package/build/contracts/SafeMath.json +1 -1
- package/build/contracts/SignedOperationProxy.json +21 -104
- package/build/contracts/SimpleFeeOwner.json +18 -63
- package/build/contracts/State.json +9 -9
- package/build/contracts/Storage.json +37 -37
- package/build/contracts/TestAmmRebalancerProxy.json +32 -58
- package/build/contracts/TestAutoTrader.json +22 -22
- package/build/contracts/TestBtcUsdChainlinkAggregator.json +10 -10
- package/build/contracts/TestCallee.json +19 -19
- package/build/contracts/TestChainlinkPriceOracleV1.json +10 -94
- package/build/contracts/TestCounter.json +7 -7
- package/build/contracts/TestDaiUsdChainlinkAggregator.json +11 -11
- package/build/contracts/TestDolomiteMargin.json +22 -22
- package/build/contracts/TestDoubleExponentInterestSetter.json +10 -10
- package/build/contracts/TestEthUsdChainlinkAggregator.json +11 -11
- package/build/contracts/TestExchangeWrapper.json +28 -28
- package/build/contracts/TestInterestSetter.json +13 -13
- package/build/contracts/TestLib.json +22 -22
- package/build/contracts/TestLinkUsdChainlinkAggregator.json +11 -11
- package/build/contracts/TestLiquidateCallback.json +719 -719
- package/build/contracts/TestLiquidationCallback.json +13 -13
- package/build/contracts/TestLrcEthChainlinkAggregator.json +11 -11
- package/build/contracts/TestMakerOracle.json +10 -10
- package/build/contracts/TestMaticUsdChainlinkAggregator.json +10 -10
- package/build/contracts/TestOasisDex.json +12 -12
- package/build/contracts/TestOperationImpl.json +14 -14
- package/build/contracts/TestPolynomialInterestSetter.json +10 -10
- package/build/contracts/TestPriceAggregator.json +9 -9
- package/build/contracts/TestPriceOracle.json +13 -13
- package/build/contracts/TestRecyclableToken.json +9 -9
- package/build/contracts/TestSimpleCallee.json +15 -15
- package/build/contracts/TestToken.json +9 -9
- package/build/contracts/TestTrader.json +17 -17
- package/build/contracts/TestUniswapAmmRebalancerProxy.json +16 -16
- package/build/contracts/TestUsdcUsdChainlinkAggregator.json +11 -11
- package/build/contracts/TestWETH.json +9 -9
- package/build/contracts/Time.json +9 -9
- package/build/contracts/Token.json +9 -9
- package/build/contracts/TokenA.json +10 -10
- package/build/contracts/TokenB.json +10 -10
- package/build/contracts/TokenC.json +10 -10
- package/build/contracts/TokenD.json +10 -10
- package/build/contracts/TokenE.json +10 -10
- package/build/contracts/TokenF.json +10 -10
- package/build/contracts/TransferProxy.json +22 -28
- package/build/contracts/TypedSignature.json +9 -9
- package/build/contracts/Types.json +9 -9
- package/build/contracts/UQ112x112.json +7 -7
- package/build/contracts/UniswapV2ERC20.json +7 -7
- package/build/contracts/UniswapV2Factory.json +12 -12
- package/build/contracts/UniswapV2Library.json +20 -20
- package/build/contracts/UniswapV2Pair.json +17 -17
- package/build/contracts/UniswapV2Router02.json +16 -16
- package/build/contracts/WETH9.json +1 -1
- package/contracts/external/amm/DolomiteAmmERC20.sol +135 -0
- package/contracts/external/amm/DolomiteAmmFactory.sol +122 -0
- package/contracts/external/amm/DolomiteAmmPair.sol +573 -0
- package/contracts/external/amm/SimpleFeeOwner.sol +107 -0
- package/contracts/external/helpers/LiquidatorProxyHelper.sol +252 -0
- package/contracts/external/helpers/OnlyDolomiteMargin.sol +63 -0
- package/contracts/external/interestsetters/DoubleExponentInterestSetter.sol +212 -0
- package/contracts/external/interestsetters/PolynomialInterestSetter.sol +205 -0
- package/contracts/external/interfaces/IChainlinkAggregator.sol +33 -0
- package/contracts/external/interfaces/IDolomiteAmmERC20.sol +52 -0
- package/contracts/external/interfaces/IDolomiteAmmFactory.sol +42 -0
- package/contracts/external/interfaces/IDolomiteAmmPair.sol +116 -0
- package/contracts/external/interfaces/IExpiry.sol +70 -0
- package/contracts/external/interfaces/IMakerOracle.sol +52 -0
- package/contracts/external/interfaces/IOasisDex.sol +326 -0
- package/contracts/external/interfaces/ITransferProxy.sol +53 -0
- package/contracts/external/interfaces/IUniswapV2Router.sol +134 -0
- package/contracts/external/lib/AdvancedMath.sol +23 -0
- package/contracts/external/lib/DolomiteAmmLibrary.sol +323 -0
- package/contracts/external/lib/TypedSignature.sol +120 -0
- package/contracts/external/lib/UQ112x112.sol +22 -0
- package/contracts/external/multisig/DelayedMultiSig.sol +206 -0
- package/contracts/external/multisig/MultiSig.sol +571 -0
- package/contracts/external/multisig/PartiallyDelayedMultiSig.sol +174 -0
- package/contracts/external/oracles/ChainlinkPriceOracleV1.sol +197 -0
- package/contracts/external/oracles/TestChainlinkPriceOracleV1.sol +98 -0
- package/contracts/external/proxies/AmmRebalancerProxyV1.sol +465 -0
- package/contracts/external/proxies/DolomiteAmmRouterProxy.sol +877 -0
- package/contracts/external/proxies/LiquidatorProxyV1.sol +507 -0
- package/contracts/external/proxies/LiquidatorProxyV1WithAmm.sol +574 -0
- package/contracts/external/proxies/PayableProxy.sol +146 -0
- package/contracts/external/proxies/RecyclableTokenProxy.sol +463 -0
- package/contracts/external/proxies/SignedOperationProxy.sol +553 -0
- package/contracts/external/proxies/TransferProxy.sol +207 -0
- package/contracts/external/traders/Expiry.sol +532 -0
- package/contracts/external/uniswap-v2/UniswapV2ERC20.sol +118 -0
- package/contracts/external/uniswap-v2/UniswapV2Factory.sol +67 -0
- package/contracts/external/uniswap-v2/UniswapV2Pair.sol +283 -0
- package/contracts/external/uniswap-v2/UniswapV2Router02.sol +566 -0
- package/contracts/external/uniswap-v2/interfaces/IUniswapV2Callee.sol +13 -0
- package/contracts/external/uniswap-v2/interfaces/IUniswapV2Factory.sol +18 -0
- package/contracts/external/uniswap-v2/interfaces/IUniswapV2Pair.sol +67 -0
- package/contracts/external/uniswap-v2/interfaces/IWETH.sol +7 -0
- package/contracts/external/uniswap-v2/libraries/SafeETH.sol +29 -0
- package/contracts/external/uniswap-v2/libraries/UniswapV2Library.sol +117 -0
- package/contracts/external/utils/MultiCall.sol +95 -0
- package/contracts/protocol/impl/artifacts/OperationImpl.json +80 -0
- package/contracts/protocol/impl/artifacts/OperationImpl_metadata.json +193 -0
- package/dist/build/published_contracts/AdminImpl.json +2 -2
- package/dist/build/published_contracts/AmmRebalancerProxyV1.json +5 -0
- package/dist/build/published_contracts/ChainlinkPriceOracleV1.json +1 -1
- package/dist/build/published_contracts/DolomiteAmmFactory.json +1 -1
- package/dist/build/published_contracts/DolomiteAmmRouterProxy.json +1 -1
- package/dist/build/published_contracts/DoubleExponentInterestSetter.json +2 -2
- package/dist/build/published_contracts/Expiry.json +1 -1
- package/dist/build/published_contracts/LiquidatorProxyV1.json +1 -1
- package/dist/build/published_contracts/LiquidatorProxyV1WithAmm.json +1 -1
- package/dist/build/published_contracts/MultiCall.json +1 -1
- package/dist/build/published_contracts/PayableProxy.json +2 -2
- package/dist/build/published_contracts/SignedOperationProxy.json +2 -2
- package/dist/build/published_contracts/SimpleFeeOwner.json +1 -1
- package/dist/build/published_contracts/TestUniswapAmmRebalancerProxy.json +140 -0
- package/dist/build/published_contracts/TransferProxy.json +1 -1
- package/dist/src/lib/Contracts.d.ts +3 -1
- package/dist/src/lib/Contracts.js +7 -3
- package/dist/src/lib/Contracts.js.map +1 -1
- 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
|
+
}
|