@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,574 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
Copyright 2019 dYdX Trading Inc.
|
|
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 { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
|
|
23
|
+
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
|
|
24
|
+
|
|
25
|
+
import { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol";
|
|
26
|
+
|
|
27
|
+
import { Account } from "../../protocol/lib/Account.sol";
|
|
28
|
+
import { Actions } from "../../protocol/lib/Actions.sol";
|
|
29
|
+
import { Decimal } from "../../protocol/lib/Decimal.sol";
|
|
30
|
+
import { Interest } from "../../protocol/lib/Interest.sol";
|
|
31
|
+
import { Math } from "../../protocol/lib/Math.sol";
|
|
32
|
+
import { Monetary } from "../../protocol/lib/Monetary.sol";
|
|
33
|
+
import { Require } from "../../protocol/lib/Require.sol";
|
|
34
|
+
import { Time } from "../../protocol/lib/Time.sol";
|
|
35
|
+
import { Types } from "../../protocol/lib/Types.sol";
|
|
36
|
+
|
|
37
|
+
import { LiquidatorProxyHelper } from "../helpers/LiquidatorProxyHelper.sol";
|
|
38
|
+
import { IExpiry } from "../interfaces/IExpiry.sol";
|
|
39
|
+
|
|
40
|
+
import { DolomiteAmmRouterProxy } from "./DolomiteAmmRouterProxy.sol";
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @title LiquidatorProxyV1WithAmm
|
|
45
|
+
* @author Dolomite
|
|
46
|
+
*
|
|
47
|
+
* Contract for liquidating other accounts in DolomiteMargin and atomically selling off collateral via Dolomite AMM
|
|
48
|
+
* markets.
|
|
49
|
+
*/
|
|
50
|
+
contract LiquidatorProxyV1WithAmm is ReentrancyGuard, LiquidatorProxyHelper {
|
|
51
|
+
using Math for uint256;
|
|
52
|
+
using SafeMath for uint256;
|
|
53
|
+
using Types for Types.Par;
|
|
54
|
+
using Types for Types.Wei;
|
|
55
|
+
|
|
56
|
+
// ============ Constants ============
|
|
57
|
+
|
|
58
|
+
bytes32 constant FILE = "LiquidatorProxyV1WithAmm";
|
|
59
|
+
|
|
60
|
+
// ============ Structs ============
|
|
61
|
+
|
|
62
|
+
struct Constants {
|
|
63
|
+
IDolomiteMargin dolomiteMargin;
|
|
64
|
+
Account.Info solidAccount;
|
|
65
|
+
Account.Info liquidAccount;
|
|
66
|
+
MarketInfo[] markets;
|
|
67
|
+
uint256[] liquidMarkets;
|
|
68
|
+
IExpiry expiryProxy;
|
|
69
|
+
uint32 expiry;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
struct LiquidatorProxyWithAmmCache {
|
|
73
|
+
// mutable
|
|
74
|
+
uint256 toLiquidate;
|
|
75
|
+
// The amount of heldMarket the solidAccount will receive. Includes the liquidation reward.
|
|
76
|
+
uint256 solidHeldUpdateWithReward;
|
|
77
|
+
Types.Wei solidHeldWei;
|
|
78
|
+
Types.Wei liquidHeldWei;
|
|
79
|
+
Types.Wei liquidOwedWei;
|
|
80
|
+
|
|
81
|
+
// immutable
|
|
82
|
+
uint256 heldMarket;
|
|
83
|
+
uint256 owedMarket;
|
|
84
|
+
uint256 heldPrice;
|
|
85
|
+
uint256 owedPrice;
|
|
86
|
+
uint256 owedPriceAdj;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ============ Events ============
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param solidAccountOwner The liquidator's address
|
|
93
|
+
* @param solidAccountOwner The liquidator's account number
|
|
94
|
+
* @param heldMarket The held market (collateral) that will be received by the liquidator
|
|
95
|
+
* @param heldDeltaWeiWithReward The amount of heldMarket the liquidator will receive, including the reward
|
|
96
|
+
* (positive number)
|
|
97
|
+
* @param profitHeldWei The amount of profit the liquidator will realize by performing the liquidation
|
|
98
|
+
* and atomically selling off the collateral. Can be negative or positive.
|
|
99
|
+
* @param owedMarket The debt market that will be received by the liquidator
|
|
100
|
+
* @param owedDeltaWei The amount of owedMarket that will be received by the liquidator (negative
|
|
101
|
+
* number)
|
|
102
|
+
*/
|
|
103
|
+
event LogLiquidateWithAmm(
|
|
104
|
+
address indexed solidAccountOwner,
|
|
105
|
+
uint solidAccountNumber,
|
|
106
|
+
uint heldMarket,
|
|
107
|
+
uint heldDeltaWeiWithReward,
|
|
108
|
+
Types.Wei profitHeldWei, // calculated as `heldWeiWithReward - soldHeldWeiToBreakEven`
|
|
109
|
+
uint owedMarket,
|
|
110
|
+
uint owedDeltaWei
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// ============ Storage ============
|
|
114
|
+
|
|
115
|
+
IDolomiteMargin DOLOMITE_MARGIN;
|
|
116
|
+
DolomiteAmmRouterProxy ROUTER_PROXY;
|
|
117
|
+
IExpiry EXPIRY_PROXY;
|
|
118
|
+
|
|
119
|
+
// ============ Constructor ============
|
|
120
|
+
|
|
121
|
+
constructor (
|
|
122
|
+
address dolomiteMargin,
|
|
123
|
+
address dolomiteAmmRouterProxy,
|
|
124
|
+
address expiryProxy
|
|
125
|
+
)
|
|
126
|
+
public
|
|
127
|
+
{
|
|
128
|
+
DOLOMITE_MARGIN = IDolomiteMargin(dolomiteMargin);
|
|
129
|
+
ROUTER_PROXY = DolomiteAmmRouterProxy(dolomiteAmmRouterProxy);
|
|
130
|
+
EXPIRY_PROXY = IExpiry(expiryProxy);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ============ Public Functions ============
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Liquidate liquidAccount using solidAccount. This contract and the msg.sender to this contract
|
|
137
|
+
* must both be operators for the solidAccount.
|
|
138
|
+
*
|
|
139
|
+
* @param solidAccount The account that will do the liquidating
|
|
140
|
+
* @param liquidAccount The account that will be liquidated
|
|
141
|
+
* @param owedMarket The owed market whose borrowed value will be added to `toLiquidate`
|
|
142
|
+
* @param heldMarket The held market whose collateral will be recovered to take on the debt of
|
|
143
|
+
* `owedMarket`
|
|
144
|
+
* @param tokenPath The path through which the trade will be routed to recover the collateral
|
|
145
|
+
* @param expiry The time at which the position expires, if this liquidation is for closing
|
|
146
|
+
* an expired position. Else, 0.
|
|
147
|
+
* @param minOwedOutputAmount The minimum amount that should be outputted by the trade from heldWei to
|
|
148
|
+
* owedWei. Used to prevent sandwiching and mem-pool other attacks. Only used
|
|
149
|
+
* if `revertOnFailToSellCollateral` is set to `false` and the collateral
|
|
150
|
+
* cannot cover the `liquidAccount`'s debt.
|
|
151
|
+
* @param revertOnFailToSellCollateral True to revert the transaction completely if all collateral from the
|
|
152
|
+
* liquidation cannot repay the owed debt. False to swallow the error and sell
|
|
153
|
+
* whatever is possible. If set to false, the liquidator must have sufficient
|
|
154
|
+
* assets to be prevent becoming liquidated or under-collateralized.
|
|
155
|
+
*/
|
|
156
|
+
function liquidate(
|
|
157
|
+
Account.Info memory solidAccount,
|
|
158
|
+
Account.Info memory liquidAccount,
|
|
159
|
+
uint256 owedMarket,
|
|
160
|
+
uint256 heldMarket,
|
|
161
|
+
address[] memory tokenPath,
|
|
162
|
+
uint expiry,
|
|
163
|
+
uint minOwedOutputAmount,
|
|
164
|
+
bool revertOnFailToSellCollateral
|
|
165
|
+
)
|
|
166
|
+
public
|
|
167
|
+
nonReentrant
|
|
168
|
+
{
|
|
169
|
+
Require.that(
|
|
170
|
+
owedMarket != heldMarket,
|
|
171
|
+
FILE,
|
|
172
|
+
"owedMarket equals heldMarket",
|
|
173
|
+
owedMarket,
|
|
174
|
+
heldMarket
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
Require.that(
|
|
178
|
+
!DOLOMITE_MARGIN.getAccountPar(liquidAccount, owedMarket).isPositive(),
|
|
179
|
+
FILE,
|
|
180
|
+
"owed market cannot be positive",
|
|
181
|
+
owedMarket
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
Require.that(
|
|
185
|
+
DOLOMITE_MARGIN.getAccountPar(liquidAccount, heldMarket).isPositive(),
|
|
186
|
+
FILE,
|
|
187
|
+
"held market cannot be negative",
|
|
188
|
+
heldMarket
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
Require.that(
|
|
192
|
+
uint32(expiry) == expiry,
|
|
193
|
+
FILE,
|
|
194
|
+
"expiry overflow",
|
|
195
|
+
expiry
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
// put all values that will not change into a single struct
|
|
199
|
+
Constants memory constants;
|
|
200
|
+
constants.dolomiteMargin = DOLOMITE_MARGIN;
|
|
201
|
+
constants.solidAccount = solidAccount;
|
|
202
|
+
constants.liquidAccount = liquidAccount;
|
|
203
|
+
constants.liquidMarkets = constants.dolomiteMargin.getAccountMarketsWithNonZeroBalances(liquidAccount);
|
|
204
|
+
constants.markets = getMarketInfos(
|
|
205
|
+
constants.dolomiteMargin,
|
|
206
|
+
constants.dolomiteMargin.getAccountMarketsWithNonZeroBalances(solidAccount),
|
|
207
|
+
constants.liquidMarkets
|
|
208
|
+
);
|
|
209
|
+
constants.expiryProxy = expiry > 0 ? EXPIRY_PROXY: IExpiry(address(0));
|
|
210
|
+
constants.expiry = uint32(expiry);
|
|
211
|
+
|
|
212
|
+
LiquidatorProxyWithAmmCache memory cache = initializeCache(
|
|
213
|
+
constants,
|
|
214
|
+
heldMarket,
|
|
215
|
+
owedMarket
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// validate the msg.sender and that the liquidAccount can be liquidated
|
|
219
|
+
checkRequirements(
|
|
220
|
+
constants,
|
|
221
|
+
heldMarket,
|
|
222
|
+
owedMarket,
|
|
223
|
+
tokenPath
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// get the max liquidation amount
|
|
227
|
+
calculateMaxLiquidationAmount(cache);
|
|
228
|
+
|
|
229
|
+
// if nothing to liquidate, do nothing
|
|
230
|
+
Require.that(
|
|
231
|
+
cache.toLiquidate != 0,
|
|
232
|
+
FILE,
|
|
233
|
+
"nothing to liquidate"
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
uint totalSolidHeldWei = cache.solidHeldUpdateWithReward;
|
|
237
|
+
if (cache.solidHeldWei.sign) {
|
|
238
|
+
// If the solid account has held wei, add the amount the solid account will receive from liquidation to its
|
|
239
|
+
// total held wei
|
|
240
|
+
// We do this so we can accurately track how much the solid account has (and will have after the swap), in
|
|
241
|
+
// case we need to input it exactly to Router#getParamsForSwapExactTokensForTokens
|
|
242
|
+
totalSolidHeldWei = totalSolidHeldWei.add(cache.solidHeldWei.value);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
(
|
|
246
|
+
Account.Info[] memory accounts,
|
|
247
|
+
Actions.ActionArgs[] memory actions
|
|
248
|
+
) = ROUTER_PROXY.getParamsForSwapTokensForExactTokens(
|
|
249
|
+
constants.solidAccount.owner,
|
|
250
|
+
constants.solidAccount.number,
|
|
251
|
+
uint(- 1), // maxInputWei
|
|
252
|
+
cache.toLiquidate, // the amount of owedMarket that needs to be repaid. Exact output amount
|
|
253
|
+
tokenPath
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
if (cache.solidHeldUpdateWithReward >= actions[0].amount.value) {
|
|
257
|
+
uint profit = cache.solidHeldUpdateWithReward.sub(actions[0].amount.value);
|
|
258
|
+
uint _owedMarket = owedMarket; // used to prevent the "stack too deep" error
|
|
259
|
+
emit LogLiquidateWithAmm(
|
|
260
|
+
constants.solidAccount.owner,
|
|
261
|
+
constants.solidAccount.number,
|
|
262
|
+
heldMarket,
|
|
263
|
+
cache.solidHeldUpdateWithReward,
|
|
264
|
+
Types.Wei(true, profit),
|
|
265
|
+
_owedMarket,
|
|
266
|
+
cache.toLiquidate
|
|
267
|
+
);
|
|
268
|
+
} else {
|
|
269
|
+
Require.that(
|
|
270
|
+
!revertOnFailToSellCollateral,
|
|
271
|
+
FILE,
|
|
272
|
+
"totalSolidHeldWei is too small",
|
|
273
|
+
totalSolidHeldWei,
|
|
274
|
+
actions[0].amount.value
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// This value needs to be calculated before `actions` is overwritten below with the new swap parameters
|
|
278
|
+
uint profit = actions[0].amount.value.sub(cache.solidHeldUpdateWithReward);
|
|
279
|
+
(accounts, actions) = ROUTER_PROXY.getParamsForSwapExactTokensForTokens(
|
|
280
|
+
constants.solidAccount.owner,
|
|
281
|
+
constants.solidAccount.number,
|
|
282
|
+
totalSolidHeldWei, // inputWei
|
|
283
|
+
minOwedOutputAmount,
|
|
284
|
+
tokenPath
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
uint _owedMarket = owedMarket; // used to prevent the "stack too deep" error
|
|
288
|
+
emit LogLiquidateWithAmm(
|
|
289
|
+
constants.solidAccount.owner,
|
|
290
|
+
constants.solidAccount.number,
|
|
291
|
+
heldMarket,
|
|
292
|
+
cache.solidHeldUpdateWithReward,
|
|
293
|
+
Types.Wei(false, profit),
|
|
294
|
+
_owedMarket,
|
|
295
|
+
cache.toLiquidate
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
accounts = constructAccountsArray(constants, accounts);
|
|
300
|
+
|
|
301
|
+
// execute the liquidations
|
|
302
|
+
constants.dolomiteMargin.operate(
|
|
303
|
+
accounts,
|
|
304
|
+
constructActionsArray(constants, cache, accounts, actions) //solium-disable-line arg-overflow
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ============ Calculation Functions ============
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Calculate the additional owedAmount that can be liquidated until the collateralization of the
|
|
312
|
+
* liquidator account reaches the minLiquidatorRatio. By this point, the cache will be set such
|
|
313
|
+
* that the amount of owedMarket is non-positive and the amount of heldMarket is non-negative.
|
|
314
|
+
*/
|
|
315
|
+
function calculateMaxLiquidationAmount(
|
|
316
|
+
LiquidatorProxyWithAmmCache memory cache
|
|
317
|
+
)
|
|
318
|
+
private
|
|
319
|
+
pure
|
|
320
|
+
{
|
|
321
|
+
uint liquidHeldValue = cache.heldPrice.mul(cache.liquidHeldWei.value);
|
|
322
|
+
uint liquidOwedValue = cache.owedPriceAdj.mul(cache.liquidOwedWei.value);
|
|
323
|
+
if (liquidHeldValue <= liquidOwedValue) {
|
|
324
|
+
// The user is under-collateralized; there is no reward left to give
|
|
325
|
+
cache.solidHeldUpdateWithReward = cache.liquidHeldWei.value;
|
|
326
|
+
cache.toLiquidate = Math.getPartialRoundUp(cache.liquidHeldWei.value, cache.heldPrice, cache.owedPriceAdj);
|
|
327
|
+
} else {
|
|
328
|
+
cache.solidHeldUpdateWithReward = Math.getPartial(
|
|
329
|
+
cache.liquidOwedWei.value,
|
|
330
|
+
cache.owedPriceAdj,
|
|
331
|
+
cache.heldPrice
|
|
332
|
+
);
|
|
333
|
+
cache.toLiquidate = cache.liquidOwedWei.value;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ============ Helper Functions ============
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Make some basic checks before attempting to liquidate an account.
|
|
341
|
+
* - Require that the msg.sender has the permission to use the liquidator account
|
|
342
|
+
* - Require that the liquid account is liquidatable based on the accounts global value (all assets held and owed,
|
|
343
|
+
* not just what's being liquidated)
|
|
344
|
+
*/
|
|
345
|
+
function checkRequirements(
|
|
346
|
+
Constants memory constants,
|
|
347
|
+
uint256 heldMarket,
|
|
348
|
+
uint256 owedMarket,
|
|
349
|
+
address[] memory tokenPath
|
|
350
|
+
)
|
|
351
|
+
private
|
|
352
|
+
view
|
|
353
|
+
{
|
|
354
|
+
// check credentials for msg.sender
|
|
355
|
+
Require.that(
|
|
356
|
+
constants.solidAccount.owner == msg.sender
|
|
357
|
+
|| constants.dolomiteMargin.getIsLocalOperator(constants.solidAccount.owner, msg.sender),
|
|
358
|
+
FILE,
|
|
359
|
+
"Sender not operator",
|
|
360
|
+
constants.solidAccount.owner
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
Require.that(
|
|
364
|
+
constants.dolomiteMargin.getMarketIdByTokenAddress(tokenPath[0]) == heldMarket,
|
|
365
|
+
FILE,
|
|
366
|
+
"0-index token path incorrect",
|
|
367
|
+
tokenPath[0]
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
Require.that(
|
|
371
|
+
constants.dolomiteMargin.getMarketIdByTokenAddress(tokenPath[tokenPath.length - 1]) == owedMarket,
|
|
372
|
+
FILE,
|
|
373
|
+
"last-index token path incorrect",
|
|
374
|
+
tokenPath[tokenPath.length - 1]
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
if (constants.expiry == 0) {
|
|
378
|
+
// user is getting liquidated, not expired. Check liquid account is indeed liquid
|
|
379
|
+
(
|
|
380
|
+
Monetary.Value memory liquidSupplyValue,
|
|
381
|
+
Monetary.Value memory liquidBorrowValue
|
|
382
|
+
) = getAdjustedAccountValues(
|
|
383
|
+
constants.dolomiteMargin,
|
|
384
|
+
constants.markets,
|
|
385
|
+
constants.liquidAccount,
|
|
386
|
+
constants.liquidMarkets
|
|
387
|
+
);
|
|
388
|
+
Require.that(
|
|
389
|
+
liquidSupplyValue.value != 0,
|
|
390
|
+
FILE,
|
|
391
|
+
"Liquid account no supply"
|
|
392
|
+
);
|
|
393
|
+
Require.that(
|
|
394
|
+
constants.dolomiteMargin.getAccountStatus(constants.liquidAccount) == Account.Status.Liquid ||
|
|
395
|
+
!isCollateralized(
|
|
396
|
+
liquidSupplyValue.value,
|
|
397
|
+
liquidBorrowValue.value,
|
|
398
|
+
constants.dolomiteMargin.getMarginRatio()
|
|
399
|
+
),
|
|
400
|
+
FILE,
|
|
401
|
+
"Liquid account not liquidatable"
|
|
402
|
+
);
|
|
403
|
+
} else {
|
|
404
|
+
// check the expiration is valid; to get here we already know constants.expiry != 0
|
|
405
|
+
uint expiry = constants.expiryProxy.getExpiry(constants.liquidAccount, owedMarket);
|
|
406
|
+
Require.that(
|
|
407
|
+
expiry == constants.expiry,
|
|
408
|
+
FILE,
|
|
409
|
+
"expiry mismatch",
|
|
410
|
+
expiry,
|
|
411
|
+
constants.expiry
|
|
412
|
+
);
|
|
413
|
+
Require.that(
|
|
414
|
+
expiry <= Time.currentTime(),
|
|
415
|
+
FILE,
|
|
416
|
+
"Borrow not yet expired",
|
|
417
|
+
expiry
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Returns true if the supplyValue over-collateralizes the borrowValue by the ratio.
|
|
424
|
+
*/
|
|
425
|
+
function isCollateralized(
|
|
426
|
+
uint256 supplyValue,
|
|
427
|
+
uint256 borrowValue,
|
|
428
|
+
Decimal.D256 memory ratio
|
|
429
|
+
)
|
|
430
|
+
private
|
|
431
|
+
pure
|
|
432
|
+
returns (bool)
|
|
433
|
+
{
|
|
434
|
+
uint256 requiredMargin = Decimal.mul(borrowValue, ratio);
|
|
435
|
+
return supplyValue >= borrowValue.add(requiredMargin);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// ============ Getter Functions ============
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Pre-populates cache values for some pair of markets.
|
|
442
|
+
*/
|
|
443
|
+
function initializeCache(
|
|
444
|
+
Constants memory constants,
|
|
445
|
+
uint256 heldMarket,
|
|
446
|
+
uint256 owedMarket
|
|
447
|
+
)
|
|
448
|
+
private
|
|
449
|
+
view
|
|
450
|
+
returns (LiquidatorProxyWithAmmCache memory)
|
|
451
|
+
{
|
|
452
|
+
MarketInfo memory heldMarketInfo = binarySearch(constants.markets, heldMarket);
|
|
453
|
+
MarketInfo memory owedMarketInfo = binarySearch(constants.markets, owedMarket);
|
|
454
|
+
uint256 heldPrice = heldMarketInfo.price.value;
|
|
455
|
+
uint256 owedPrice = owedMarketInfo.price.value;
|
|
456
|
+
|
|
457
|
+
uint256 owedPriceAdj;
|
|
458
|
+
if (constants.expiry > 0) {
|
|
459
|
+
(, Monetary.Price memory owedPricePrice) = constants.expiryProxy.getSpreadAdjustedPrices(
|
|
460
|
+
heldMarket,
|
|
461
|
+
owedMarket,
|
|
462
|
+
constants.expiry
|
|
463
|
+
);
|
|
464
|
+
owedPriceAdj = owedPricePrice.value;
|
|
465
|
+
} else {
|
|
466
|
+
owedPriceAdj = Decimal.mul(
|
|
467
|
+
owedPrice,
|
|
468
|
+
Decimal.onePlus(constants.dolomiteMargin.getLiquidationSpreadForPair(heldMarket, owedMarket))
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return LiquidatorProxyWithAmmCache({
|
|
473
|
+
toLiquidate: 0,
|
|
474
|
+
solidHeldUpdateWithReward: 0,
|
|
475
|
+
solidHeldWei: Interest.parToWei(
|
|
476
|
+
constants.dolomiteMargin.getAccountPar(constants.solidAccount, heldMarket),
|
|
477
|
+
heldMarketInfo.index
|
|
478
|
+
),
|
|
479
|
+
liquidHeldWei: Interest.parToWei(
|
|
480
|
+
constants.dolomiteMargin.getAccountPar(constants.liquidAccount, heldMarket),
|
|
481
|
+
heldMarketInfo.index
|
|
482
|
+
),
|
|
483
|
+
liquidOwedWei: Interest.parToWei(
|
|
484
|
+
constants.dolomiteMargin.getAccountPar(constants.liquidAccount, owedMarket),
|
|
485
|
+
owedMarketInfo.index
|
|
486
|
+
),
|
|
487
|
+
heldMarket: heldMarket,
|
|
488
|
+
owedMarket: owedMarket,
|
|
489
|
+
heldPrice: heldPrice,
|
|
490
|
+
owedPrice: owedPrice,
|
|
491
|
+
owedPriceAdj: owedPriceAdj
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// ============ Operation-Construction Functions ============
|
|
496
|
+
|
|
497
|
+
function constructAccountsArray(
|
|
498
|
+
Constants memory constants,
|
|
499
|
+
Account.Info[] memory accountsForTrade
|
|
500
|
+
)
|
|
501
|
+
private
|
|
502
|
+
pure
|
|
503
|
+
returns (Account.Info[] memory)
|
|
504
|
+
{
|
|
505
|
+
Account.Info[] memory accounts = new Account.Info[](accountsForTrade.length + 1);
|
|
506
|
+
for (uint i = 0; i < accountsForTrade.length; i++) {
|
|
507
|
+
accounts[i] = accountsForTrade[i];
|
|
508
|
+
}
|
|
509
|
+
assert(
|
|
510
|
+
accounts[0].owner == constants.solidAccount.owner &&
|
|
511
|
+
accounts[0].number == constants.solidAccount.number
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
accounts[accounts.length - 1] = constants.liquidAccount;
|
|
515
|
+
return accounts;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function constructActionsArray(
|
|
519
|
+
Constants memory constants,
|
|
520
|
+
LiquidatorProxyWithAmmCache memory cache,
|
|
521
|
+
Account.Info[] memory accounts,
|
|
522
|
+
Actions.ActionArgs[] memory actionsForTrade
|
|
523
|
+
)
|
|
524
|
+
private
|
|
525
|
+
pure
|
|
526
|
+
returns (Actions.ActionArgs[] memory)
|
|
527
|
+
{
|
|
528
|
+
Actions.ActionArgs[] memory actions = new Actions.ActionArgs[](actionsForTrade.length + 1);
|
|
529
|
+
|
|
530
|
+
if (constants.expiry > 0) {
|
|
531
|
+
// First action is a trade for closing the expired account
|
|
532
|
+
// accountId is solidAccount; otherAccountId is liquidAccount
|
|
533
|
+
actions[0] = Actions.ActionArgs({
|
|
534
|
+
actionType: Actions.ActionType.Trade,
|
|
535
|
+
accountId: 0,
|
|
536
|
+
amount: Types.AssetAmount({
|
|
537
|
+
sign: true,
|
|
538
|
+
denomination: Types.AssetDenomination.Wei,
|
|
539
|
+
ref: Types.AssetReference.Delta,
|
|
540
|
+
value: cache.toLiquidate
|
|
541
|
+
}),
|
|
542
|
+
primaryMarketId: cache.owedMarket,
|
|
543
|
+
secondaryMarketId: cache.heldMarket,
|
|
544
|
+
otherAddress: address(constants.expiryProxy),
|
|
545
|
+
otherAccountId: accounts.length - 1,
|
|
546
|
+
data: abi.encode(cache.owedMarket, constants.expiry)
|
|
547
|
+
});
|
|
548
|
+
} else {
|
|
549
|
+
// First action is a liquidation
|
|
550
|
+
// accountId is solidAccount; otherAccountId is liquidAccount
|
|
551
|
+
actions[0] = Actions.ActionArgs({
|
|
552
|
+
actionType: Actions.ActionType.Liquidate,
|
|
553
|
+
accountId: 0,
|
|
554
|
+
amount: Types.AssetAmount({
|
|
555
|
+
sign: true,
|
|
556
|
+
denomination: Types.AssetDenomination.Wei,
|
|
557
|
+
ref: Types.AssetReference.Delta,
|
|
558
|
+
value: cache.toLiquidate
|
|
559
|
+
}),
|
|
560
|
+
primaryMarketId: cache.owedMarket,
|
|
561
|
+
secondaryMarketId: cache.heldMarket,
|
|
562
|
+
otherAddress: address(0),
|
|
563
|
+
otherAccountId: accounts.length - 1,
|
|
564
|
+
data: new bytes(0)
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
for (uint i = 0; i < actionsForTrade.length; i++) {
|
|
569
|
+
actions[i + 1] = actionsForTrade[i];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return actions;
|
|
573
|
+
}
|
|
574
|
+
}
|