@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,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
|
+
}
|