-
Notifications
You must be signed in to change notification settings - Fork 567
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Split pool logic into libraries
- Add `PoolBaseLogic` - Add `PoolHelperLogic` - Move `ExecuteBorrowParams` to `DataTypes` - Update Pool to use libraries
- Loading branch information
Showing
7 changed files
with
562 additions
and
305 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,298 @@ | ||
// SPDX-License-Identifier: agpl-3.0 | ||
pragma solidity 0.8.6; | ||
|
||
import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol'; | ||
import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol'; | ||
|
||
import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol'; | ||
import {IAToken} from '../../../interfaces/IAToken.sol'; | ||
|
||
import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.sol'; | ||
|
||
import {ValidationLogic} from './ValidationLogic.sol'; | ||
import {ReserveLogic} from './ReserveLogic.sol'; | ||
|
||
import {Helpers} from '../helpers/Helpers.sol'; | ||
|
||
import {UserConfiguration} from './../configuration/UserConfiguration.sol'; | ||
|
||
import {DataTypes} from '../types/DataTypes.sol'; | ||
|
||
import {WadRayMath} from '../math/WadRayMath.sol'; | ||
|
||
library PoolBaseLogic { | ||
using ReserveLogic for DataTypes.ReserveCache; | ||
using ReserveLogic for DataTypes.ReserveData; | ||
using SafeERC20 for IERC20; | ||
using UserConfiguration for DataTypes.UserConfigurationMap; | ||
using WadRayMath for uint256; | ||
|
||
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); | ||
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); | ||
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); | ||
event Deposit( | ||
address indexed reserve, | ||
address user, | ||
address indexed onBehalfOf, | ||
uint256 amount, | ||
uint16 indexed referral | ||
); | ||
event Borrow( | ||
address indexed reserve, | ||
address user, | ||
address indexed onBehalfOf, | ||
uint256 amount, | ||
uint256 borrowRateMode, | ||
uint256 borrowRate, | ||
uint16 indexed referral | ||
); | ||
event Repay( | ||
address indexed reserve, | ||
address indexed user, | ||
address indexed repayer, | ||
uint256 amount | ||
); | ||
|
||
function _validateHFAndLtv( | ||
address asset, | ||
mapping(address => DataTypes.ReserveData) storage reserves, | ||
DataTypes.UserConfigurationMap storage userConfig, | ||
mapping(uint256 => address) storage reservesList, | ||
uint256 reservesCount, | ||
address priceOracle | ||
) internal view { | ||
ValidationLogic.validateHFAndLtv( | ||
asset, | ||
msg.sender, | ||
reserves, | ||
userConfig, | ||
reservesList, | ||
reservesCount, | ||
priceOracle | ||
); | ||
} | ||
|
||
function _executeDeposit( | ||
DataTypes.ReserveData storage reserve, | ||
DataTypes.UserConfigurationMap storage userConfig, | ||
address asset, | ||
uint256 amount, | ||
address onBehalfOf, | ||
uint16 referralCode | ||
) public { | ||
DataTypes.ReserveCache memory reserveCache = reserve.cache(); | ||
|
||
reserve.updateState(reserveCache); | ||
|
||
ValidationLogic.validateDeposit(reserveCache, amount); | ||
|
||
reserve.updateInterestRates(reserveCache, asset, amount, 0); | ||
|
||
IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, amount); | ||
|
||
bool isFirstDeposit = | ||
IAToken(reserveCache.aTokenAddress).mint(onBehalfOf, amount, reserveCache.nextLiquidityIndex); | ||
|
||
if (isFirstDeposit) { | ||
userConfig.setUsingAsCollateral(reserve.id, true); | ||
emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf); | ||
} | ||
|
||
emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode); | ||
} | ||
|
||
function _executeWithdraw( | ||
mapping(address => DataTypes.ReserveData) storage reserves, | ||
DataTypes.UserConfigurationMap storage userConfig, | ||
address asset, | ||
uint256 amount, | ||
address to, | ||
mapping(uint256 => address) storage reservesList, | ||
uint256 reservesCount, | ||
address priceOracle | ||
) public returns (uint256) { | ||
DataTypes.ReserveData storage reserve = reserves[asset]; | ||
DataTypes.ReserveCache memory reserveCache = reserve.cache(); | ||
|
||
reserve.updateState(reserveCache); | ||
|
||
uint256 userBalance = | ||
IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul( | ||
reserveCache.nextLiquidityIndex | ||
); | ||
|
||
uint256 amountToWithdraw = amount; | ||
|
||
if (amount == type(uint256).max) { | ||
amountToWithdraw = userBalance; | ||
} | ||
|
||
ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance); | ||
|
||
reserve.updateInterestRates(reserveCache, asset, 0, amountToWithdraw); | ||
|
||
IAToken(reserveCache.aTokenAddress).burn( | ||
msg.sender, | ||
to, | ||
amountToWithdraw, | ||
reserveCache.nextLiquidityIndex | ||
); | ||
|
||
if (userConfig.isUsingAsCollateral(reserve.id)) { | ||
if (userConfig.isBorrowingAny()) { | ||
_validateHFAndLtv(asset, reserves, userConfig, reservesList, reservesCount, priceOracle); | ||
} | ||
|
||
if (amountToWithdraw == userBalance) { | ||
userConfig.setUsingAsCollateral(reserve.id, false); | ||
emit ReserveUsedAsCollateralDisabled(asset, msg.sender); | ||
} | ||
} | ||
|
||
emit Withdraw(asset, msg.sender, to, amountToWithdraw); | ||
|
||
return amountToWithdraw; | ||
} | ||
|
||
function _executeBorrow( | ||
mapping(address => DataTypes.ReserveData) storage reserves, | ||
DataTypes.ReserveCache memory reserveCache, | ||
DataTypes.UserConfigurationMap storage userConfig, | ||
DataTypes.ExecuteBorrowParams memory vars | ||
) public { | ||
DataTypes.ReserveData storage reserve = reserves[vars.asset]; | ||
|
||
uint256 currentStableRate = 0; | ||
bool isFirstBorrowing = false; | ||
|
||
if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) { | ||
currentStableRate = reserve.currentStableBorrowRate; | ||
isFirstBorrowing = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint( | ||
vars.user, | ||
vars.onBehalfOf, | ||
vars.amount, | ||
currentStableRate | ||
); | ||
reserveCache.refreshDebt(vars.amount, 0, 0, 0); | ||
} else { | ||
isFirstBorrowing = IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint( | ||
vars.user, | ||
vars.onBehalfOf, | ||
vars.amount, | ||
reserveCache.nextVariableBorrowIndex | ||
); | ||
reserveCache.refreshDebt(0, 0, vars.amount, 0); | ||
} | ||
|
||
if (isFirstBorrowing) { | ||
userConfig.setBorrowing(reserve.id, true); | ||
} | ||
|
||
reserve.updateInterestRates( | ||
reserveCache, | ||
vars.asset, | ||
0, | ||
vars.releaseUnderlying ? vars.amount : 0 | ||
); | ||
|
||
if (vars.releaseUnderlying) { | ||
IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); | ||
} | ||
|
||
emit Borrow( | ||
vars.asset, | ||
vars.user, | ||
vars.onBehalfOf, | ||
vars.amount, | ||
vars.interestRateMode, | ||
DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE | ||
? currentStableRate | ||
: reserve.currentVariableBorrowRate, | ||
vars.referralCode | ||
); | ||
} | ||
|
||
function _executeRepay( | ||
DataTypes.ReserveData storage reserve, | ||
DataTypes.UserConfigurationMap storage userConfig, | ||
address asset, | ||
uint256 amount, | ||
uint256 rateMode, | ||
address onBehalfOf, | ||
address lastBorrower, | ||
uint40 lastBorrowTimestamp | ||
) public returns (uint256) { | ||
DataTypes.ReserveCache memory reserveCache = reserve.cache(); | ||
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); | ||
DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); | ||
|
||
ValidationLogic.validateRepay( | ||
lastBorrower, | ||
lastBorrowTimestamp, | ||
reserveCache, | ||
amount, | ||
interestRateMode, | ||
onBehalfOf, | ||
stableDebt, | ||
variableDebt | ||
); | ||
|
||
uint256 paybackAmount = | ||
interestRateMode == DataTypes.InterestRateMode.STABLE ? stableDebt : variableDebt; | ||
|
||
if (amount < paybackAmount) { | ||
paybackAmount = amount; | ||
} | ||
|
||
reserve.updateState(reserveCache); | ||
|
||
if (interestRateMode == DataTypes.InterestRateMode.STABLE) { | ||
IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); | ||
reserveCache.refreshDebt(0, paybackAmount, 0, 0); | ||
} else { | ||
IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn( | ||
onBehalfOf, | ||
paybackAmount, | ||
reserveCache.nextVariableBorrowIndex | ||
); | ||
reserveCache.refreshDebt(0, 0, 0, paybackAmount); | ||
} | ||
|
||
return | ||
_executeRepayHelper( | ||
reserve, | ||
reserveCache, | ||
userConfig, | ||
asset, | ||
onBehalfOf, | ||
paybackAmount, | ||
variableDebt, | ||
stableDebt | ||
); | ||
} | ||
|
||
function _executeRepayHelper( | ||
DataTypes.ReserveData storage reserve, | ||
DataTypes.ReserveCache memory reserveCache, | ||
DataTypes.UserConfigurationMap storage userConfig, | ||
address asset, | ||
address onBehalfOf, | ||
uint256 paybackAmount, | ||
uint256 variableDebt, | ||
uint256 stableDebt | ||
) public returns (uint256) { | ||
reserve.updateInterestRates(reserveCache, asset, paybackAmount, 0); | ||
|
||
if (stableDebt + variableDebt - paybackAmount == 0) { | ||
userConfig.setBorrowing(reserve.id, false); | ||
} | ||
|
||
IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, paybackAmount); | ||
|
||
IAToken(reserveCache.aTokenAddress).handleRepayment(msg.sender, paybackAmount); | ||
|
||
emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); | ||
|
||
return paybackAmount; | ||
} | ||
} |
Oops, something went wrong.