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 }