UNPKG

@dolomite-exchange/dolomite-margin

Version:

Ethereum Smart Contracts and TypeScript library used for the DolomiteMargin trading protocol

689 lines (688 loc) 1.43 MB
{ "contractName": "LiquidatorProxyBase", "abi": [ { "inputs": [ { "internalType": "uint256", "name": "_chainId", "type": "uint256" } ], "payable": false, "stateMutability": "nonpayable", "type": "constructor" }, { "constant": true, "inputs": [], "name": "LIQUIDATOR_ASSET_REGISTRY", "outputs": [ { "internalType": "contract ILiquidatorAssetRegistry", "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "chainId", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" } ], "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_chainId\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"constant\":true,\"inputs\":[],\"name\":\"LIQUIDATOR_ASSET_REGISTRY\",\"outputs\":[{\"internalType\":\"contract ILiquidatorAssetRegistry\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Dolomite * Inheritable contract that allows sharing code across different liquidator proxy contracts\",\"methods\":{},\"title\":\"LiquidatorProxyBase\"},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"/home/cdc218/projects/dolomite-protocol-v2/contracts/external/helpers/LiquidatorProxyBase.sol\":\"LiquidatorProxyBase\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"/home/cdc218/projects/dolomite-protocol-v2/contracts/external/helpers/HasLiquidatorRegistry.sol\":{\"keccak256\":\"0xf7fb6d26d662f5a7ae5df8e30110664c7254f1a4969c31a3504e166018358e42\",\"urls\":[\"bzz-raw://b1a8adc3fdddce8ad10ce2420570b73218c3dd23238ab0000938051194834389\",\"dweb:/ipfs/QmPE47PxyM2xEat3xCWkiogpNRGkx26KLePGQZhGRGJpk8\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/external/helpers/LiquidatorProxyBase.sol\":{\"keccak256\":\"0x5a7bc34966d0bbaf860283dff729819733c6aeb2d74969de4faa77a38ed0e580\",\"urls\":[\"bzz-raw://4fc391dc8defc010d4736300e52159039540d881b256a62f425de790da44cd48\",\"dweb:/ipfs/QmWGcvumKySkGmCPtGQcw3e6X1Fz17e33mV7QpXr9fgWpV\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/external/interfaces/IExpiry.sol\":{\"keccak256\":\"0xa7b197139e570e823cab42c3b8500c9c5edc8a40110970a7d6fe60f05864ba10\",\"urls\":[\"bzz-raw://4f469be063d8f694c5277650bc53ac2c0d164f62e36c6a9ab7dad126479990a9\",\"dweb:/ipfs/Qme4sTbGi4T2QhsJSweqGzqm5rxQkypy27g1vLy8ipVijV\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/external/interfaces/ILiquidatorAssetRegistry.sol\":{\"keccak256\":\"0x0d99615ee12fad08fbdf59a67683af9c7cdcfd2f25cf20b6767ebb6988eec514\",\"urls\":[\"bzz-raw://90230d7a44d9936cda8d1b1fef170daf91750b97d3da9634ed6c079fb8dbd15a\",\"dweb:/ipfs/QmfQxDE36en2hecxS4Y2i4BH6TsSEDEzKNxooysW4GsdKb\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/external/lib/DolomiteVersionLib.sol\":{\"keccak256\":\"0x2b53e388a5307c028d1be1ab654eacb46bd445b24beb367c0782bd408f2a28b4\",\"urls\":[\"bzz-raw://f1b9f5d89093f45e4b83c3220c2a426f4e399c7bd4ba0a6fa95e1ac6a25f77f6\",\"dweb:/ipfs/QmdoQ2xZnB7r7q2i1gEkzn5KyuiDQW1oAjDUHB6x6DG8Fy\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IAccountRiskOverrideSetter.sol\":{\"keccak256\":\"0x5b9fde139ddfdaae7b650b3c3f6699e0e44605f0d9d3daadc1622eb06ad4c3f8\",\"urls\":[\"bzz-raw://2dfd5af24b6de63f94519c99fd8777a264d7cd11266fa2d525c7d72d96a9c7cf\",\"dweb:/ipfs/QmPg9fjhbnmBayZMh6yTG79xsK1PWSoAHA5pfwSXfnKKjF\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IDolomiteMargin.sol\":{\"keccak256\":\"0x7e86ed1ed04dc205245db9f4e7cf7cca60c3bfc46c57ade8129a463780647967\",\"urls\":[\"bzz-raw://f8fbd85afd334c12bdccbb6523ebea9172b27b7b4b132c4a48b4b4dd03ceeb2b\",\"dweb:/ipfs/QmU1srfSqBTz3kw7oz1KEzfTUJvphZiE4K8MRZcy9uJjv1\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IERC20Detailed.sol\":{\"keccak256\":\"0x22a62e2a8155e70300773721902f4b9118e17aa0bb5d9d1b046050a014cfb223\",\"urls\":[\"bzz-raw://03af737a33c552fbe58f6f1fbd5496854fdc28dd57be4365d56663725c083a18\",\"dweb:/ipfs/QmbgLqGAQEd6tXsZB8QaPNCAMiU6nNzP75wNbKdS65BuUF\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IInterestSetter.sol\":{\"keccak256\":\"0x546825f65490a30e29d0f6446acec49c1e895ce6b33d48ca5c05092725a63a57\",\"urls\":[\"bzz-raw://6ad3013aed985bdf6e6234ae0f7f37e6bba76c3470c33bfa24678cf19b3b412c\",\"dweb:/ipfs/QmfYaSBzxGpgiHoR7ontMJY66S5L26XwkLYoEuzsEjpbQH\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IOracleSentinel.sol\":{\"keccak256\":\"0xa94499fda55ef112640daed2cb1d06062e72c51c7b925c323b4e0ffa9b456ce5\",\"urls\":[\"bzz-raw://18b4a16acac577590a57f34f7ec6583e3cb35f575c948abb928b308d29cac1ab\",\"dweb:/ipfs/QmR1jLkzj6w7SjrdZ7GVW4V2vofSdMJwzjTqKpeUKABvxu\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IPriceOracle.sol\":{\"keccak256\":\"0x3f7c3d1397390ea44c6d5e5730d49476431c3df3b28334fe38218de5edc31138\",\"urls\":[\"bzz-raw://63ebf926fca9ce33aaabaf93805686acc25daded1648d6dab59c8c4d05116918\",\"dweb:/ipfs/QmeGkDp7ycYstpfqCYBiqoCYwy876gabx8r42o5koj3H5A\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Account.sol\":{\"keccak256\":\"0x2059276ea5e478bd5ac7f2712e7b1b6c85d291c647a54b264909044844828e67\",\"urls\":[\"bzz-raw://f153777051d12131b13a57e5c3af10a2670927cfc7d22c9519ab20c9b4b9bc89\",\"dweb:/ipfs/QmQMP3qS5xDAVGYKDfNkbkSqBKozQGQsGqX4e8VyjRtxPS\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Actions.sol\":{\"keccak256\":\"0x7b2fcf441c034952dd042b6c8b20b148359db771e7c9ac07d06369560a9f0301\",\"urls\":[\"bzz-raw://84665ee4a780360fe6160d197ba98f0bf0ab0d7c6ad87bfed6226bf2f88d8d30\",\"dweb:/ipfs/QmRDfRdAd8hSXeu4SAeeYKkKoXBhStu7n4uReYBce2JD5Z\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Bits.sol\":{\"keccak256\":\"0x6d9a641163b2dd25e648c65f5d9e4949a57938e29ddc4c9dddefd74a9964aeef\",\"urls\":[\"bzz-raw://67e5a04ed4055faafbc100d6ccca9c54448ed378a1a8c71171562edda7bcbf7c\",\"dweb:/ipfs/QmYRikK3Xbgiq3UBJkgoo2zNUSSrShVabpRHmQj6iQHhrc\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Cache.sol\":{\"keccak256\":\"0xe57c80a7621a77fcb2acb9f883fb5248e71a6dce03bc2db56df0db3fee332950\",\"urls\":[\"bzz-raw://28e221c04629674490b9a0041d4f9a5f15e669dc0cc192a5df6e2c701c36369f\",\"dweb:/ipfs/QmaL3oh8c7v9cx91pB175pyCEuzxnhNTab4UxmBMsDYfUx\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Decimal.sol\":{\"keccak256\":\"0xd9a348c2b1eec076609ba12bbec6b9c2e4ea135790a7ef4f5411feb050af2144\",\"urls\":[\"bzz-raw://d5bcff29e47d5cd02d7a9966e9f44c46ccbb4f0e4adfc4b0b86646880677db39\",\"dweb:/ipfs/QmRKfJD4FFM1AvTynSFNx1NcDg94o9SAcjz7dvMaJCfecp\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/DolomiteMarginMath.sol\":{\"keccak256\":\"0x53f205f6a779d579be29faa9412c806a892b3e605fff092dfd9d14d936fa019f\",\"urls\":[\"bzz-raw://0ff936f89602a63b8e6a4eb4ce8f87673c0f45b7ce29694920905a3f0b5a6a69\",\"dweb:/ipfs/QmbYME9BeEvPC1ndV8EaUDX5fDMghLc3rocNUxFtgHmg8m\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/EnumerableSet.sol\":{\"keccak256\":\"0x41a3460e34b7b8635d936e35e6568ceb5354b638f53b884530e0d4875fa0f151\",\"urls\":[\"bzz-raw://d1a5ba866ee95d455afe5075dadd91fc71c2806371f2c1b358a1f67c632bb0df\",\"dweb:/ipfs/QmW4qCjmsG8J3UJv97GwDLDM7wt1K4yLDKAwzWMY7TFYi5\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Interest.sol\":{\"keccak256\":\"0x141a0ecb4a746f0e5767df4b99dbe33c6362df507ae9d5c02da1c1c17bc26df3\",\"urls\":[\"bzz-raw://9ff03e64a8ce5231acde07788624bf8c7a8ff55d90b157fa32f62fa887a0eff0\",\"dweb:/ipfs/QmUVxxWeE954RDXbmHJAYnHsXcit6rSXGqZUigu8t9oH2z\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Monetary.sol\":{\"keccak256\":\"0x5257274f2d4d3605f3e97ec45fb902111fe9a22506f0b4cf308ea933bc81bfe2\",\"urls\":[\"bzz-raw://85b8023b78805063a2ec8d376f1f5983994eabd96efd8ceadb0224dbb71c5678\",\"dweb:/ipfs/QmaDhzCzRqsuHuJfhToEC4pATQHwhh7yWWsjwfuRzFT1kG\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Require.sol\":{\"keccak256\":\"0x05a2a90b41b6a5f42f0a72da63d015fb0b406a9ba2172823352e522e8bf3a606\",\"urls\":[\"bzz-raw://19883f0c6d33266f756ec5c3d17539524aa24b993c46c33f8400801d09373a6c\",\"dweb:/ipfs/QmYX2fwK3vQQDSZLMrc5wMfeb8RWrcC9CGX8XECLty8QDk\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Storage.sol\":{\"keccak256\":\"0x9c27f3cd52af28c9b6bca18097b1793f114d08284d78417467d0d05f67e9e2a9\",\"urls\":[\"bzz-raw://d1ed0e7a7f76d59f30572996d4e164ab8fb5b2ec4bfca127983f9e936b904813\",\"dweb:/ipfs/QmePVYbgrY8Yw3Vf76pmEvE9pX916Jaa9we4kjM8tGM4J1\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Time.sol\":{\"keccak256\":\"0x87ee8d3c1d6e315a116426d8c8fc6f083e220fd14dda27fad4e8d7cab3dc7305\",\"urls\":[\"bzz-raw://7c20f2c52da682c3b5917fb6a19e81f43699b1d13c62b569ed723f34da72e766\",\"dweb:/ipfs/QmbXWYXi67nHBVNDKYUpo2E9ZaEVcHLvmXQkpYLMm1d5Vm\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Token.sol\":{\"keccak256\":\"0x095b5f8eb3665f6e246200311efc8a654fa3e90f9a1a522e27a4d089e8ab3917\",\"urls\":[\"bzz-raw://5db812b752a03d601d424e6e21be38153477082af0acf51b5c98eefa5553ed18\",\"dweb:/ipfs/QmbE549QUXYTurpx8hSMLBJvuBpfYqyNE6FBCgHJDY8PLf\"]},\"/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Types.sol\":{\"keccak256\":\"0xe1bab8c8799d83e86c7a49aaf815d8e3bc8d09562d46d44d921500db5e98de0e\",\"urls\":[\"bzz-raw://8ea3d0cc4fdab6dd9bba545a792170f939b342d8d1a7051c1c6365009af72658\",\"dweb:/ipfs/QmaLJgbavu88eEit6JPqfWnw6NmGBDZfveMXxumgWywBFG\"]},\"@openzeppelin/contracts/math/SafeMath.sol\":{\"keccak256\":\"0x640b6dee7a4b830bdfd52b5031a07fc2b12209f5b2e29e5d364a7d37f69d8076\",\"urls\":[\"bzz-raw://31113152e1ddb78fe7a4197f247591ca894e93f916867beb708d8e747b6cc74f\",\"dweb:/ipfs/QmbZaJyXdpsYGykVhHH9qpVGQg9DGCxE2QufbCUy3daTgq\"]},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xe5bb0f57cff3e299f360052ba50f1ea0fff046df2be070b6943e0e3c3fdad8a9\",\"urls\":[\"bzz-raw://59fd025151435da35faa8093a5c7a17de02de9d08ad27275c5cdf05050820d91\",\"dweb:/ipfs/QmQMvwEcPhoRXzbXyrdoeRtvLoifUW9Qh7Luho7bmUPRkc\"]}},\"version\":1}", "bytecode": "0x", "deployedBytecode": "0x", "sourceMap": "", "deployedSourceMap": "", "source": "/*\n\n Copyright 2022 Dolomite.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma solidity ^0.5.7;\npragma experimental ABIEncoderV2;\n\nimport { SafeMath } from \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport { IDolomiteMargin } from \"../../protocol/interfaces/IDolomiteMargin.sol\";\nimport { IExpiry } from \"../interfaces/IExpiry.sol\";\nimport { ILiquidatorAssetRegistry } from \"../interfaces/ILiquidatorAssetRegistry.sol\";\n\nimport { DolomiteVersionLib } from \"../lib/DolomiteVersionLib.sol\";\n\nimport { Account } from \"../../protocol/lib/Account.sol\";\nimport { Bits } from \"../../protocol/lib/Bits.sol\";\nimport { Decimal } from \"../../protocol/lib/Decimal.sol\";\nimport { DolomiteMarginMath } from \"../../protocol/lib/DolomiteMarginMath.sol\";\nimport { Interest } from \"../../protocol/lib/Interest.sol\";\nimport { Monetary } from \"../../protocol/lib/Monetary.sol\";\nimport { Require } from \"../../protocol/lib/Require.sol\";\nimport { Time } from \"../../protocol/lib/Time.sol\";\nimport { Types } from \"../../protocol/lib/Types.sol\";\n\nimport { HasLiquidatorRegistry } from \"./HasLiquidatorRegistry.sol\";\n\n\n/**\n * @title LiquidatorProxyBase\n * @author Dolomite\n *\n * Inheritable contract that allows sharing code across different liquidator proxy contracts\n */\ncontract LiquidatorProxyBase is HasLiquidatorRegistry {\n using DolomiteVersionLib for *;\n using SafeMath for uint;\n using Types for Types.Par;\n\n // ============ Constants ============\n\n bytes32 private constant FILE = \"LiquidatorProxyBase\";\n uint256 private constant MAX_UINT_BITS = 256;\n uint256 private constant ONE = 1;\n\n // ============ Structs ============\n\n struct MarketInfo {\n uint256 marketId;\n Monetary.Price price;\n Interest.Index index;\n }\n\n struct LiquidatorProxyConstants {\n IDolomiteMargin dolomiteMargin;\n Account.Info solidAccount;\n Account.Info liquidAccount;\n uint256 heldMarket;\n uint256 owedMarket;\n MarketInfo[] markets;\n uint256[] liquidMarkets;\n IExpiry expiryProxy;\n uint32 expiry;\n }\n\n struct LiquidatorProxyCache {\n // mutable\n uint256 owedWeiToLiquidate;\n // The amount of heldMarket the solidAccount will receive. Includes the liquidation reward. Useful as the\n // `amountIn` for a trade\n uint256 solidHeldUpdateWithReward;\n Types.Wei solidHeldWei;\n Types.Wei solidOwedWei;\n Types.Wei liquidHeldWei;\n Types.Wei liquidOwedWei;\n // This exists purely for expirations. If the amount being repaid is meant to be ALL but the value of the debt\n // is greater than the value of the collateral, then we need to flip the markets in the trade for the Target=0\n // encoding of the Amount. There's a rounding issue otherwise because amounts are calculated differently for\n // trades vs. liquidations\n bool flipMarketsForExpiration;\n\n // immutable\n uint256 heldPrice;\n uint256 owedPrice;\n uint256 owedPriceAdj;\n }\n\n // ============ Fields ============\n\n uint256 public chainId;\n\n // ============ Internal Functions ============\n\n constructor(uint256 _chainId) internal {\n chainId = _chainId;\n }\n\n /**\n * Pre-populates cache values for some pair of markets.\n */\n function _initializeCache(\n LiquidatorProxyConstants memory _constants\n )\n internal\n view\n returns (LiquidatorProxyCache memory)\n {\n MarketInfo memory heldMarketInfo = _binarySearch(_constants.markets, _constants.heldMarket);\n MarketInfo memory owedMarketInfo = _binarySearch(_constants.markets, _constants.owedMarket);\n\n uint256 owedPriceAdj;\n if (_constants.expiry != 0) {\n (, Monetary.Price memory owedPricePrice) = _constants.expiryProxy.getExpirySpreadAdjustedPricesForChain(\n chainId,\n _constants.liquidAccount,\n _constants.heldMarket,\n _constants.owedMarket,\n _constants.expiry\n );\n owedPriceAdj = owedPricePrice.value;\n } else {\n Decimal.D256 memory spread = _constants.dolomiteMargin.getLiquidationSpreadForChainAndPair(\n chainId,\n _constants.liquidAccount,\n _constants.heldMarket,\n _constants.owedMarket\n );\n owedPriceAdj = owedMarketInfo.price.value.add(Decimal.mul(owedMarketInfo.price.value, spread));\n }\n\n return LiquidatorProxyCache({\n owedWeiToLiquidate: 0,\n solidHeldUpdateWithReward: 0,\n solidHeldWei: Interest.parToWei(\n _constants.dolomiteMargin.getAccountPar(_constants.solidAccount, _constants.heldMarket),\n heldMarketInfo.index\n ),\n solidOwedWei: Interest.parToWei(\n _constants.dolomiteMargin.getAccountPar(_constants.solidAccount, _constants.owedMarket),\n owedMarketInfo.index\n ),\n liquidHeldWei: Interest.parToWei(\n _constants.dolomiteMargin.getAccountPar(_constants.liquidAccount, _constants.heldMarket),\n heldMarketInfo.index\n ),\n liquidOwedWei: Interest.parToWei(\n _constants.dolomiteMargin.getAccountPar(_constants.liquidAccount, _constants.owedMarket),\n owedMarketInfo.index\n ),\n flipMarketsForExpiration: false,\n heldPrice: heldMarketInfo.price.value,\n owedPrice: owedMarketInfo.price.value,\n owedPriceAdj: owedPriceAdj\n });\n }\n\n /**\n * Make some basic checks before attempting to liquidate an account.\n * - Require that the msg.sender has the permission to use the liquidator account\n * - Require that the liquid account is liquidatable based on the accounts global value (all assets held and owed,\n * not just what's being liquidated)\n */\n function _checkConstants(\n LiquidatorProxyConstants memory _constants,\n uint256 _expiry\n )\n internal\n view\n {\n // panic if the developer didn't set these variables already\n assert(address(_constants.dolomiteMargin) != address(0));\n assert(_constants.solidAccount.owner != address(0));\n assert(_constants.liquidAccount.owner != address(0));\n\n Require.that(\n _constants.owedMarket != _constants.heldMarket,\n FILE,\n \"Owed market equals held market\",\n _constants.owedMarket\n );\n\n Require.that(\n !_constants.dolomiteMargin.getAccountPar(_constants.liquidAccount, _constants.owedMarket).isPositive(),\n FILE,\n \"Owed market cannot be positive\",\n _constants.owedMarket\n );\n\n Require.that(\n _constants.dolomiteMargin.getAccountPar(_constants.liquidAccount, _constants.heldMarket).isPositive(),\n FILE,\n \"Held market cannot be negative\",\n _constants.heldMarket\n );\n\n Require.that(\n uint32(_expiry) == _expiry,\n FILE,\n \"Expiry overflows\",\n _expiry\n );\n\n Require.that(\n _expiry <= Time.currentTime(),\n FILE,\n \"Borrow not yet expired\",\n _expiry\n );\n }\n\n /**\n * Make some basic checks before attempting to liquidate an account.\n * - Require that the msg.sender has the permission to use the solid account\n * - Require that the expiration timestamp matches the real expiry, if processing an expiration\n */\n function _checkBasicRequirements(\n LiquidatorProxyConstants memory _constants\n )\n internal\n view\n {\n // check credentials for msg.sender\n Require.that(\n _constants.solidAccount.owner == msg.sender\n || _constants.dolomiteMargin.getIsLocalOperator(_constants.solidAccount.owner, msg.sender),\n FILE,\n \"Sender not operator\",\n msg.sender\n );\n\n if (_constants.expiry != 0) {\n // check the expiration is valid; to get here we already know constants.expiry != 0\n uint32 expiry = _constants.expiryProxy.getExpiry(_constants.liquidAccount, _constants.owedMarket);\n Require.that(\n expiry == _constants.expiry,\n FILE,\n \"Expiry mismatch\",\n expiry,\n _constants.expiry\n );\n }\n }\n\n /**\n * Calculate the maximum amount that can be liquidated on `liquidAccount`\n */\n function _calculateAndSetMaxLiquidationAmount(\n LiquidatorProxyCache memory _cache\n )\n internal\n pure\n {\n uint256 liquidHeldValue = _cache.heldPrice.mul(_cache.liquidHeldWei.value);\n uint256 liquidOwedValue = _cache.owedPriceAdj.mul(_cache.liquidOwedWei.value);\n if (liquidHeldValue < liquidOwedValue) {\n // The held collateral is worth less than the adjusted debt\n _cache.solidHeldUpdateWithReward = _cache.liquidHeldWei.value;\n _cache.owedWeiToLiquidate = DolomiteMarginMath.getPartialRoundUp(\n _cache.liquidHeldWei.value,\n _cache.heldPrice,\n _cache.owedPriceAdj\n );\n _cache.flipMarketsForExpiration = true;\n } else {\n _cache.solidHeldUpdateWithReward = DolomiteMarginMath.getPartial(\n _cache.liquidOwedWei.value,\n _cache.owedPriceAdj,\n _cache.heldPrice\n );\n _cache.owedWeiToLiquidate = _cache.liquidOwedWei.value;\n }\n }\n\n function _calculateAndSetActualLiquidationAmount(\n uint256 _minOutputAmountWei,\n LiquidatorProxyCache memory _cache\n )\n internal\n pure\n returns (uint256 _newMinOutputAmountWei)\n {\n // at this point, _cache.owedWeiToLiquidate should be the max amount that can be liquidated on the user.\n assert(_cache.owedWeiToLiquidate != 0); // assert it was initialized\n\n _newMinOutputAmountWei = _minOutputAmountWei;\n\n if (_newMinOutputAmountWei == uint256(-1)) {\n _newMinOutputAmountWei = _cache.owedWeiToLiquidate;\n } else if (_newMinOutputAmountWei < _cache.owedWeiToLiquidate) {\n _cache.owedWeiToLiquidate = _newMinOutputAmountWei;\n _cache.solidHeldUpdateWithReward = DolomiteMarginMath.getPartial(\n _newMinOutputAmountWei,\n _cache.owedPriceAdj,\n _cache.heldPrice\n );\n }\n }\n\n /**\n * Returns true if the supplyValue over-collateralizes the borrowValue by the ratio.\n */\n function _isCollateralized(\n uint256 supplyValue,\n uint256 borrowValue,\n Decimal.D256 memory ratio\n )\n internal\n pure\n returns (bool)\n {\n uint256 requiredMargin = Decimal.mul(borrowValue, ratio);\n return supplyValue >= borrowValue.add(requiredMargin);\n }\n\n /**\n * Gets the current total supplyValue and borrowValue for some account. Takes into account what\n * the current index will be once updated.\n */\n function _getAccountValues(\n IDolomiteMargin dolomiteMargin,\n MarketInfo[] memory marketInfos,\n Account.Info memory account,\n uint256[] memory marketIds,\n Decimal.D256 memory marginRatioOverride\n )\n internal\n view\n returns (\n Monetary.Value memory,\n Monetary.Value memory\n )\n {\n return _getAccountValues(\n dolomiteMargin,\n marketInfos,\n account,\n marketIds,\n /* adjustForMarginPremiums = */ false, // solium-disable-line indentation\n marginRatioOverride\n );\n }\n\n /**\n * Gets the adjusted current total supplyValue and borrowValue for some account. Takes into account what\n * the current index will be once updated and the margin premium.\n */\n function _getAdjustedAccountValues(\n IDolomiteMargin dolomiteMargin,\n MarketInfo[] memory marketInfos,\n Account.Info memory account,\n uint256[] memory marketIds,\n Decimal.D256 memory marginRatioOverride\n )\n internal\n view\n returns (\n Monetary.Value memory,\n Monetary.Value memory\n )\n {\n return _getAccountValues(\n dolomiteMargin,\n marketInfos,\n account,\n marketIds,\n /* adjustForMarginPremiums = */ true, // solium-disable-line indentation\n marginRatioOverride\n );\n }\n\n function _getMarketInfos(\n IDolomiteMargin dolomiteMargin,\n uint256[] memory solidMarkets,\n uint256[] memory liquidMarkets\n ) internal view returns (MarketInfo[] memory) {\n uint256[] memory marketBitmaps = Bits.createBitmaps(dolomiteMargin.getNumMarkets());\n uint256 marketsLength = 0;\n marketsLength = _addMarketsToBitmap(solidMarkets, marketBitmaps, marketsLength);\n marketsLength = _addMarketsToBitmap(liquidMarkets, marketBitmaps, marketsLength);\n\n uint256 counter;\n MarketInfo[] memory marketInfos = new MarketInfo[](marketsLength);\n for (uint256 i; i < marketBitmaps.length; ++i) {\n uint256 bitmap = marketBitmaps[i];\n while (bitmap != 0) {\n uint256 nextSetBit = Bits.getLeastSignificantBit(bitmap);\n uint256 marketId = Bits.getMarketIdFromBit(i, nextSetBit);\n\n marketInfos[counter++] = MarketInfo({\n marketId: marketId,\n price: dolomiteMargin.getMarketPrice(marketId),\n index: dolomiteMargin.getMarketCurrentIndex(marketId)\n });\n\n // unset the set bit\n bitmap = Bits.unsetBit(bitmap, nextSetBit);\n }\n if (counter == marketsLength) {\n break;\n }\n }\n\n return marketInfos;\n }\n\n function _binarySearch(\n MarketInfo[] memory markets,\n uint256 marketId\n ) internal pure returns (MarketInfo memory) {\n return _binarySearch(\n markets,\n 0,\n markets.length,\n marketId\n );\n }\n\n // ============ Private Functions ============\n\n // solium-disable-next-line security/no-assign-params\n function _getAccountValues(\n IDolomiteMargin dolomiteMargin,\n MarketInfo[] memory marketInfos,\n Account.Info memory account,\n uint256[] memory marketIds,\n bool adjustForMarginPremiums,\n Decimal.D256 memory marginRatioOverride\n )\n private\n view\n returns (\n Monetary.Value memory supplyValue,\n Monetary.Value memory borrowValue\n )\n {\n\n // Only adjust for liquidity if prompted AND if there is no override\n adjustForMarginPremiums = adjustForMarginPremiums && marginRatioOverride.value == 0;\n\n for (uint256 i; i < marketIds.length; ++i) {\n Types.Par memory par = dolomiteMargin.getAccountPar(account, marketIds[i]);\n MarketInfo memory marketInfo = _binarySearch(marketInfos, marketIds[i]);\n Types.Wei memory userWei = Interest.parToWei(par, marketInfo.index);\n uint256 assetValue = userWei.value.mul(marketInfo.price.value);\n Decimal.D256 memory marginPremium = Decimal.one();\n if (adjustForMarginPremiums) {\n marginPremium = Decimal.onePlus(dolomiteMargin.getMarketMarginPremium(marketIds[i]));\n }\n if (userWei.sign) {\n supplyValue.value = supplyValue.value.add(Decimal.div(assetValue, marginPremium));\n } else {\n borrowValue.value = borrowValue.value.add(Decimal.mul(assetValue, marginPremium));\n }\n }\n\n return (supplyValue, borrowValue);\n }\n\n // solium-disable-next-line security/no-assign-params\n function _addMarketsToBitmap(\n uint256[] memory markets,\n uint256[] memory bitmaps,\n uint256 marketsLength\n ) private pure returns (uint) {\n for (uint256 i; i < markets.length; ++i) {\n if (!Bits.hasBit(bitmaps, markets[i])) {\n Bits.setBit(bitmaps, markets[i]);\n marketsLength += 1;\n }\n }\n return marketsLength;\n }\n\n function _binarySearch(\n MarketInfo[] memory markets,\n uint256 beginInclusive,\n uint256 endExclusive,\n uint256 marketId\n ) private pure returns (MarketInfo memory) {\n uint256 len = endExclusive - beginInclusive;\n // solium-disable indentation\n /* ignore-coverage */ Require.that(\n len != 0 && (len != 1 || markets[beginInclusive].marketId == marketId),\n FILE,\n \"Market not found\"\n );\n // solium-enable indentation\n\n // Calculate the mid\n uint256 mid = beginInclusive + (len >> 1);\n uint256 midMarketId = markets[mid].marketId;\n if (marketId < midMarketId) {\n return _binarySearch(\n markets,\n beginInclusive,\n mid,\n marketId\n );\n } else if (marketId > midMarketId) {\n return _binarySearch(\n markets,\n mid + 1,\n endExclusive,\n marketId\n );\n } else {\n return markets[mid];\n }\n }\n\n}\n", "sourcePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/external/helpers/LiquidatorProxyBase.sol", "ast": { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/external/helpers/LiquidatorProxyBase.sol", "exportedSymbols": { "LiquidatorProxyBase": [ 2985 ] }, "id": 2986, "nodeType": "SourceUnit", "nodes": [ { "id": 1875, "literals": [ "solidity", "^", "0.5", ".7" ], "nodeType": "PragmaDirective", "src": "595:23:5" }, { "id": 1876, "literals": [ "experimental", "ABIEncoderV2" ], "nodeType": "PragmaDirective", "src": "619:33:5" }, { "absolutePath": "@openzeppelin/contracts/math/SafeMath.sol", "file": "@openzeppelin/contracts/math/SafeMath.sol", "id": 1878, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 37366, "src": "654:69:5", "symbolAliases": [ { "foreign": 1877, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/interfaces/IDolomiteMargin.sol", "file": "../../protocol/interfaces/IDolomiteMargin.sol", "id": 1880, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 24694, "src": "725:80:5", "symbolAliases": [ { "foreign": 1879, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/external/interfaces/IExpiry.sol", "file": "../interfaces/IExpiry.sol", "id": 1882, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 4566, "src": "806:52:5", "symbolAliases": [ { "foreign": 1881, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/external/interfaces/ILiquidatorAssetRegistry.sol", "file": "../interfaces/ILiquidatorAssetRegistry.sol", "id": 1884, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 4875, "src": "859:86:5", "symbolAliases": [ { "foreign": 1883, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/external/lib/DolomiteVersionLib.sol", "file": "../lib/DolomiteVersionLib.sol", "id": 1886, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 6030, "src": "947:67:5", "symbolAliases": [ { "foreign": 1885, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Account.sol", "file": "../../protocol/lib/Account.sol", "id": 1888, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 24886, "src": "1016:57:5", "symbolAliases": [ { "foreign": 1887, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Bits.sol", "file": "../../protocol/lib/Bits.sol", "id": 1890, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 25657, "src": "1074:51:5", "symbolAliases": [ { "foreign": 1889, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Decimal.sol", "file": "../../protocol/lib/Decimal.sol", "id": 1892, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 26024, "src": "1126:57:5", "symbolAliases": [ { "foreign": 1891, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/DolomiteMarginMath.sol", "file": "../../protocol/lib/DolomiteMarginMath.sol", "id": 1894, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 26239, "src": "1184:79:5", "symbolAliases": [ { "foreign": 1893, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Interest.sol", "file": "../../protocol/lib/Interest.sol", "id": 1896, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 27751, "src": "1264:59:5", "symbolAliases": [ { "foreign": 1895, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Monetary.sol", "file": "../../protocol/lib/Monetary.sol", "id": 1898, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 27761, "src": "1324:59:5", "symbolAliases": [ { "foreign": 1897, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Require.sol", "file": "../../protocol/lib/Require.sol", "id": 1900, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 28453, "src": "1384:57:5", "symbolAliases": [ { "foreign": 1899, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Time.sol", "file": "../../protocol/lib/Time.sol", "id": 1902, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 30730, "src": "1442:51:5", "symbolAliases": [ { "foreign": 1901, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/protocol/lib/Types.sol", "file": "../../protocol/lib/Types.sol", "id": 1904, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 31362, "src": "1494:53:5", "symbolAliases": [ { "foreign": 1903, "local": null } ], "unitAlias": "" }, { "absolutePath": "/home/cdc218/projects/dolomite-protocol-v2/contracts/external/helpers/HasLiquidatorRegistry.sol", "file": "./HasLiquidatorRegistry.sol", "id": 1906, "nodeType": "ImportDirective", "scope": 2986, "sourceUnit": 1723, "src": "1549:68:5", "symbolAliases": [ { "foreign": 1905, "local": null } ], "unitAlias": "" }, { "baseContracts": [ { "arguments": null, "baseName": { "contractScope": null, "id": 1907, "name": "HasLiquidatorRegistry", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 1722, "src": "1806:21:5", "typeDescriptions": { "typeIdentifier": "t_contract$_HasLiquidatorRegistry_$1722", "typeString": "contract HasLiquidatorRegistry" } }, "id": 1908, "nodeType": "InheritanceSpecifier", "src": "1806:21:5" } ], "contractDependencies": [ 1722 ], "contractKind": "contract", "documentation": "@title LiquidatorProxyBase\n@author Dolomite\n * Inheritable contract that allows sharing code across different liquidator proxy contracts", "fullyImplemented": false, "id": 2985, "linearizedBaseContracts": [ 2985, 1722 ], "name": "LiquidatorProxyBase", "nodeType": "ContractDefinition", "nodes": [ { "id": 1910, "libraryName": { "contractScope": null, "id": 1909, "name": "DolomiteVersionLib", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 6029, "src": "1840:18:5", "typeDescriptions": { "typeIdentifier": "t_contract$_DolomiteVersionLib_$6029", "typeString": "library DolomiteVersionLib" } }, "nodeType": "UsingForDirective", "src": "1834:31:5", "typeName": null }, { "id": 1913, "libraryName": { "contractScope": null, "id": 1911, "name": "SafeMath", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 37365, "src": "1876:8:5", "typeDescriptions": { "typeIdentifier": "t_contract$_SafeMath_$37365", "typeString": "library SafeMath" } }, "nodeType": "UsingForDirective", "src": "1870:24:5", "typeName": { "id": 1912, "name": "uint", "nodeType": "ElementaryTypeName", "src": "1889:4:5", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } } }, { "id": 1916, "libraryName": { "contractScope": null, "id": 1914, "name": "Types", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 31361, "src": "1905:5:5", "typeDescriptions": { "typeIdentifier": "t_contract$_Types_$31361", "typeString": "library Types" } }, "nodeType": "UsingForDirective", "src": "1899:26:5", "typeName": { "contractScope": null, "id": 1915, "name": "Types.Par", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 30890, "src": "1915:9:5", "typeDescriptions": { "typeIdentifier": "t_struct$_Par_$30890_storage_ptr", "typeString": "struct Types.Par" } } }, { "constant": true, "id": 1919, "name": "FILE", "nodeType": "VariableDeclaration", "scope": 2985, "src": "1975:53:5", "stateVariable": true, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_bytes32", "typeString": "bytes32" }, "typeName": { "id": 1917, "name": "bytes32", "nodeType": "ElementaryTypeName", "src": "1975:7:5", "typeDescriptions": { "typeIdentifier": "t_bytes32", "typeString": "bytes32" } }, "value": { "argumentTypes": null, "hexValue": "4c697175696461746f7250726f787942617365", "id": 1918, "isConstant": false, "isLValue": false, "isPure": true, "kind": "string", "lValueRequested": false, "nodeType": "Literal", "src": "2007:21:5", "subdenomination": null, "typeDescriptions": { "typeIdentifier": "t_stringliteral_6500857aec207600459317968955519aac10f888f6f2a89006d92cccbb5d2dd4", "typeString": "literal_string \"LiquidatorProxyBase\"" }, "value": "LiquidatorProxyBase" }, "visibility": "private" }, { "constant": true, "id": 1922, "name": "MAX_UINT_BITS", "nodeType": "VariableDeclaration", "scope": 2985, "src": "2034:44:5", "stateVariable": true, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" }, "typeName": { "id": 1920, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "2034:7:5", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "value": { "argumentTypes": null, "hexValue": "323536", "id": 1921, "isConstant": false, "isLValue": false, "isPure": true, "kind": "number", "lValueRequested": false, "nodeType": "Literal", "src": "2075:3:5", "subdenomination": null, "typeDescriptions": { "typeIdentifier": "t_rational_256_by_1", "typeString": "int_const 256" }, "value": "256" }, "visibility": "private" }, { "constant": true, "id": 1925, "name": "ONE", "nodeType": "VariableDeclaration", "scope": 2985, "src": "2084:32:5", "stateVariable": true, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" }, "typeName": { "id": 1923, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "2084:7:5", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "value": { "argumentTypes": null, "hexValue": "31", "id": 1924, "isConstant": false, "isLValue": false, "isPure": true, "kind": "number", "lValueRequested": false, "nodeType": "Literal", "src": "2115:1:5", "subdenomination": null, "typeDescriptions": { "typeIdentifier": "t_rational_1_by_1", "typeString": "int_const 1" }, "value": "1" }, "visibility": "private" }, { "canonicalName": "LiquidatorProxyBase.MarketInfo", "id": 1932, "members": [ { "constant": false, "id": 1927, "name": "marketId", "nodeType": "VariableDeclaration", "scope": 1932, "src": "2193:16:5", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" }, "typeName": { "id": 1926, "name": "uint256", "nodeType": "ElementaryTypeName", "src": "2193:7:5", "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } }, "value": null, "visibility": "internal" }, { "constant": false, "id": 1929, "name": "price", "nodeType": "VariableDeclaration", "scope": 1932, "src": "2219:20:5", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_struct$_Price_$27756_storage_ptr", "typeString": "struct Monetary.Price" }, "typeName": { "contractScope": null, "id": 1928, "name": "Monetary.Price", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 27756, "src": "2219:14:5", "typeDescriptions": { "typeIdentifier": "t_struct$_Price_$27756_storage_ptr", "typeString": "struct Monetary.Price" } }, "value": null, "visibility": "internal" }, { "constant": false, "id": 1931, "name": "index", "nodeType": "VariableDeclaration", "scope": 1932, "src": "2249:20:5", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_struct$_Index_$27471_storage_ptr", "typeString": "struct Interest.Index" }, "typeName": { "contractScope": null, "id": 1930, "name": "Interest.Index", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 27471, "src": "2249:14:5", "typeDescriptions": { "typeIdentifier": "t_struct$_Index_$27471_storage_ptr", "typeString": "struct Interest.Index" } }, "value": null, "visibility": "internal" } ], "name": "MarketInfo", "nodeType": "StructDefinition", "scope": 2985, "src": "2165:111:5", "visibility": "public" }, { "canonicalName": "LiquidatorProxyBase.LiquidatorProxyConstants", "id": 1953, "members": [ { "constant": false, "id": 1934, "name": "dolomiteMargin", "nodeType": "VariableDeclaration", "scope": 1953, "src": "2324:30:5", "stateVariable": false, "storageLocation": "default", "typeDescriptions": { "typeIdentifier": "t_contract$_IDolomiteMargin_$24693", "typeString": "contract IDolomiteMargin" }, "typeName": { "contractScope": null, "id": 1933, "name": "IDolomiteMargin", "nodeType": "UserDefinedTypeName", "referencedDeclaration": 24693, "src": "2324:15:5", "typeDescriptions": { "typeIdentifier": "t_contract$_IDolomiteMargin_$24693", "typeString": "contract IDolomiteMargin" } }, "value": null, "visibility": "internal" }, { "constant": false,