/ contracts / finance / rehypothecation / InternalRehypothecationManager.sol
InternalRehypothecationManager.sol
  1  pragma solidity >=0.6.0;
  2  pragma experimental ABIEncoderV2;
  3  
  4  
  5  import "./BaseRehypothecationManager.sol";
  6  import "../../interfaces/UnderlyingFeed.sol";
  7  import "../../interfaces/IUnderlyingCreditToken.sol";
  8  import "../../interfaces/IBaseHedgingManager.sol";
  9  import "../../interfaces/IUnderlyingCreditProvider.sol";
 10  
 11  contract InternalRehypothecationManager is BaseRehypothecationManager {
 12  	uint constant _volumeBase = 1e18;
 13  
 14  	mapping(address => mapping(address => mapping(address => uint256))) lenderCommitmentIdMap;
 15  	mapping(address => mapping(address => mapping(address => uint256))) borrowerBidIdMap;
 16  	mapping(address => mapping(address => mapping(address => uint256))) notionalExposureMap;
 17  	mapping(address => mapping(address => mapping(address => uint256))) notionalExposureInExchangeBalMap;
 18  	mapping(address => mapping(address => mapping(address => uint256))) collateralAmountMap;
 19  
 20  	function notionalExposure(address account, address asset, address collateral) override external view returns (uint256) {
 21  		return notionalExposureInExchangeBalMap[account][asset][collateral];
 22  	}
 23  
 24  	function borrowExposure(address account, address asset, address collateral) override external view returns (uint256) {
 25  		return notionalExposureMap[account][asset][collateral];
 26  	}
 27  
 28  	function lend(address asset, address collateral, uint assetAmount, uint collateralAmount, address udlFeed) override external {
 29  
 30  		require(
 31              settings.isAllowedHedgingManager(msg.sender) == true, 
 32              "not allowed hedging manager"
 33          );
 34  
 35  
 36  		require(lenderCommitmentIdMap[msg.sender][asset][collateral] == 0, "already lending");
 37  		uint notional;
 38  
 39  		if (collateral == address(exchange)) {
 40  			//non stable lending (lev short), can only hedge against udl credit (collateral == exchange balance, asset == udl credit)
 41  			require(
 42          		UnderlyingFeed(udlFeed).getUnderlyingAddr() == IUnderlyingCreditToken(asset).getUdlAsset(),
 43          		"bad udlFeed"
 44          	);
 45  			uint256 udlAssetBal = IUnderlyingCreditProvider(asset).balanceOf(address(this));
 46  
 47  			(,int udlPrice) = UnderlyingFeed(udlFeed).getLatestPrice();
 48  			uint256 udlNotionalAmount = assetAmount.mul(_volumeBase).div(uint256(udlPrice));
 49  
 50  			//assetAmount / price = collateralAmount * leverage
 51  
 52  			//before loan request
 53  			if (udlAssetBal >= udlNotionalAmount){
 54  				IUnderlyingCreditProvider(asset).swapBalanceForCreditTokens(address(this), udlNotionalAmount);
 55  			} else {
 56  				if (udlAssetBal > 0) {
 57  					IUnderlyingCreditProvider(asset).swapBalanceForCreditTokens(address(this), udlAssetBal);
 58  				}	
 59  				IUnderlyingCreditProvider(asset).issueCredit(address(this), udlNotionalAmount.sub(udlAssetBal));
 60  
 61  			}
 62  
 63  			notional = udlNotionalAmount;
 64  		} else {
 65  			//stable lending (lev long), can only hedge against exchange balance (collateral == udl credit, asset == exchange balance) 
 66  			
 67  			uint256 assetBal = IERC20_2(asset).balanceOf(address(this));
 68  			//before loan request
 69  			if (assetBal < assetAmount){
 70  				creditProvider.issueCredit(address(this), assetAmount.sub(assetBal));
 71  				creditToken.swapForExchangeBalance(assetAmount.sub(assetBal));
 72  			}
 73  
 74  			notional = assetAmount;
 75  		}
 76  		
 77  		lenderCommitmentIdMap[msg.sender][asset][collateral]++;
 78  		collateralAmountMap[msg.sender][asset][collateral] = collateralAmount;
 79  	}
 80  
 81      function withdraw(address asset, address collateral, uint amount) override external {}
 82  
 83      function borrow(address asset, address collateral, uint assetAmount, uint collateralAmount, address udlFeed) override external {
 84      	require(
 85              settings.isAllowedHedgingManager(msg.sender) == true, 
 86              "not allowed hedging manager"
 87          );
 88  
 89  		require(lenderCommitmentIdMap[msg.sender][asset][collateral] > 0, "no outstanding loan");
 90  		require(borrowerBidIdMap[msg.sender][asset][collateral] == 0, "already borrowing");
 91  
 92  		require(
 93      		UnderlyingFeed(udlFeed).getUnderlyingAddr() == IUnderlyingCreditToken(asset).getUdlAsset(),
 94      		"bad udlFeed"
 95      	);
 96  
 97      	(,int udlPrice) = UnderlyingFeed(udlFeed).getLatestPrice();
 98  
 99          if (collateral == address(exchange)) {
100  			//(collateral == exchange balance, asset == udl credit)
101  			IERC20_2(collateral).safeTransferFrom(
102  	            msg.sender,
103  	            address(this), 
104  	            collateralAmount
105  	        );
106  		} else { 
107  			//(collateral == udl credit, asset == exchange balance)
108  			uint256 collateralAmountInAsset = collateralAmount.mul(uint256(udlPrice)).div(_volumeBase);
109  			//assetAmount / leverage = collateralAmount * price
110  
111  			IERC20_2(asset).safeTransferFrom(
112  	            msg.sender,
113  	            address(this), 
114  	            collateralAmountInAsset
115  	        );
116  			uint256 udlAssetBal = IUnderlyingCreditProvider(collateral).balanceOf(address(this));
117  	        //before borrow request, mint or credit the difference differing in collateral to rehypo manager
118  			if (udlAssetBal >= collateralAmount){
119  				IUnderlyingCreditProvider(asset).swapBalanceForCreditTokens(address(this), collateralAmount);
120  			} else {
121  				if (udlAssetBal > 0) {
122  					IUnderlyingCreditProvider(asset).swapBalanceForCreditTokens(address(this), udlAssetBal);
123  				}	
124  				IUnderlyingCreditProvider(asset).issueCredit(address(this), collateralAmount.sub(udlAssetBal));
125  			}
126  		}
127  
128  		if (collateral == address(exchange)) {
129  			//(collateral == exchange balance, asset == udl credit)
130  	        /*
131  
132  	        - after borrow request
133  				- swap udl credit borrowed for exchange balance at orace rate interally with agaisnt rehypo manager
134  					- mint exchange balance to rehypo manager -> transfer to pool hedging manager
135  					- rehypo manage keeps udl credit token
136  
137  			*/
138  			uint256 collateralBal = IERC20_2(collateral).balanceOf(address(this));
139  			uint256 assetAmountInCollateral = assetAmount.mul(uint256(udlPrice)).div(_volumeBase);
140  			if (collateralBal < assetAmountInCollateral){
141  				creditProvider.issueCredit(address(this), assetAmountInCollateral.sub(collateralBal));
142  				creditToken.swapForExchangeBalance(assetAmountInCollateral.sub(collateralBal));
143  			}
144  
145  			IERC20_2(collateral).safeTransfer(msg.sender, assetAmountInCollateral);
146  			notionalExposureInExchangeBalMap[msg.sender][asset][collateral] = assetAmountInCollateral;
147  		} else {
148  			//(collateral == udl credit, asset == exchange balance)
149  			/*
150  			- after borrow request
151  				- swap exchange balance borrowed for udl credit at orace rate interally with agaisnt rehypo manager
152  					- withdraw (or mint the amount short) udl credit to rehypo manager -> transfer to pool hedging manager
153  					- rehypo manage keeps exchange balance
154  			*/
155  
156  			uint256 udlAssetBal = IERC20_2(collateral).balanceOf(address(this));
157  			uint256 collateralAmountInAsset = assetAmount.mul(_volumeBase).div(uint256(udlPrice));
158  			if (udlAssetBal >= collateralAmountInAsset){
159  				IUnderlyingCreditProvider(asset).swapBalanceForCreditTokens(address(this), collateralAmountInAsset);
160  			} else {
161  				if (udlAssetBal > 0) {
162  					IUnderlyingCreditProvider(collateral).swapBalanceForCreditTokens(address(this), udlAssetBal);
163  				}	
164  				IUnderlyingCreditProvider(collateral).issueCredit(address(this), collateralAmountInAsset.sub(udlAssetBal));
165  			}
166  
167  			IERC20_2(collateral).safeTransfer(msg.sender, collateralAmountInAsset);
168  			notionalExposureInExchangeBalMap[msg.sender][asset][collateral] = assetAmount;
169  		}
170  
171  		
172  
173  		borrowerBidIdMap[msg.sender][asset][collateral] = 1;
174  		notionalExposureMap[msg.sender][asset][collateral] = assetAmount;
175      }
176      
177      function repay(address asset, address collateral, address udlFeed)  override external {
178  
179  		require(lenderCommitmentIdMap[msg.sender][asset][collateral] > 0, "no outstanding loan");
180  		require(borrowerBidIdMap[msg.sender][asset][collateral] > 0, "no outstanding borrow");
181  
182  		(,int udlPrice) = UnderlyingFeed(udlFeed).getLatestPrice();
183  
184  		/*
185  
186  		uint256 _collateralTokenId = 0;//0 for erc20's
187  	    uint32 _loanDuration = 7 days;//
188  
189  		uint256 _bidId = ITellerInterface(tellerInterfaceAddr).acceptCommitment(
190  		    lenderCommitmentIdMap[msg.sender][asset][collateral],
191  		    assetAmount,
192  		    collateralAmount,
193  		    _collateralTokenId,//0 for erc20's
194  		    collateral,
195  		    0, 
196  		    _loanDuration
197  		);
198  
199  		*/
200  
201  		if (collateral == address(exchange)) {
202  			//(collateral == exchange balance, asset == udl credit)
203  			uint256 transferAmountInCollateral = notionalExposureMap[msg.sender][asset][collateral].mul(uint(udlPrice)).div(_volumeBase);
204  			IERC20_2(collateral).safeTransferFrom(
205  	            msg.sender,
206  	            address(this), 
207  	            transferAmountInCollateral
208  	        );
209  		} else { 
210  			//(collateral == udl credit, asset == exchange balance)
211  
212  			uint256 transferAmountInAsset = notionalExposureMap[msg.sender][asset][collateral].mul(uint(udlPrice)).div(_volumeBase);
213  			uint256 udlCreditBal = IERC20_2(collateral).balanceOf(msg.sender);
214  			uint256 udlCreditBalInAsset = udlCreditBal.mul(uint(udlPrice)).div(_volumeBase);
215  			uint256 assetBal = IERC20_2(asset).balanceOf(msg.sender);
216  			IERC20_2(collateral).safeTransferFrom(
217  	            msg.sender,
218  	            address(this), 
219  	            udlCreditBal
220  	        );
221  
222  	    	uint256 diffAmountInExchangeBalance;
223  
224  			if (udlCreditBalInAsset >= transferAmountInAsset) {
225  				//transfer all udl credit bal, swap surplus into exchange bal, credit hedging manager for exchange bal diff
226  				diffAmountInExchangeBalance = udlCreditBalInAsset.sub(transferAmountInAsset);
227  				if (assetBal < diffAmountInExchangeBalance){
228  					creditProvider.issueCredit(address(this), diffAmountInExchangeBalance.sub(assetBal));
229  					creditToken.swapForExchangeBalance(diffAmountInExchangeBalance.sub(assetBal));
230  				}
231  				IERC20_2(asset).safeTransfer(msg.sender, diffAmountInExchangeBalance);
232  			} else {
233  				//transfer all, compute shortage amount, debit pool owner for exchange bal diff (protocol fees are charged for shortages)
234  				diffAmountInExchangeBalance = transferAmountInAsset.sub(udlCreditBalInAsset);
235  				creditProvider.processPayment(IBaseHedgingManager(msg.sender).pool(), address(this), diffAmountInExchangeBalance);
236  			}
237  		}
238  
239  		if (collateral == address(exchange)) {
240  			//(collateral == exchange balance, asset == udl credit)
241  			//burn udl credit value
242  			IUnderlyingCreditToken(asset).burnBalance(notionalExposureMap[msg.sender][asset][collateral]);
243  			//rehypo manager transfers exchanage balance collateral to hedging manager
244  			IERC20_2(collateral).safeTransfer(msg.sender, collateralAmountMap[msg.sender][asset][collateral]);
245  		} else { 
246  			//(collateral == udl credit, asset == exchange balance)
247  			//burn exchange balance in excess of collateral value
248  			creditToken.burnBalance(notionalExposureMap[msg.sender][asset][collateral]);
249  			//burn udl credit of collateral value
250  			IUnderlyingCreditToken(collateral).burnBalance(collateralAmountMap[msg.sender][asset][collateral]);
251  			//transfers exchanage balance collateral to hedging manager
252  			IERC20_2(asset).safeTransfer(
253  				msg.sender,
254  				collateralAmountMap[msg.sender][asset][collateral].mul(uint(udlPrice)).div(_volumeBase)
255  			);
256  		}
257  
258  		borrowerBidIdMap[msg.sender][asset][collateral] = 0;
259  		lenderCommitmentIdMap[msg.sender][asset][collateral] = 0;
260  		notionalExposureMap[msg.sender][asset][collateral] = 0;
261  		collateralAmountMap[msg.sender][asset][collateral] = 0;
262      }
263      
264      function transferTokensToCreditProvider(address tokenAddr) override external {}
265  
266      function transferTokensToVault(address tokenAddr) override external {}
267  }