Fix & Optimize contract
This commit is contained in:
@@ -96,6 +96,47 @@ contract Lending is
|
||||
_unpause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice 计算累计利息后的索引(不修改状态)
|
||||
* @param timeElapsed 经过的时间
|
||||
* @return 新的 supplyIndex 和 borrowIndex
|
||||
*/
|
||||
function accruedInterestIndices(uint256 timeElapsed) internal view returns (uint256, uint256) {
|
||||
uint256 newSupplyIndex = supplyIndex;
|
||||
uint256 newBorrowIndex = borrowIndex;
|
||||
|
||||
if (timeElapsed > 0) {
|
||||
// 计算实际的 totalSupply 和 totalBorrow(含利息)
|
||||
uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18;
|
||||
uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18;
|
||||
|
||||
uint64 utilization = LendingMath.getUtilization(totalSupply, totalBorrow);
|
||||
|
||||
// 计算供应利率和借款利率(每秒利率)
|
||||
uint64 supplyRate = LendingMath.getSupplyRate(
|
||||
utilization,
|
||||
supplyKink,
|
||||
supplyPerSecondInterestRateSlopeLow,
|
||||
supplyPerSecondInterestRateSlopeHigh,
|
||||
supplyPerSecondInterestRateBase
|
||||
);
|
||||
|
||||
uint64 borrowRate = LendingMath.getBorrowRate(
|
||||
utilization,
|
||||
borrowKink,
|
||||
borrowPerSecondInterestRateSlopeLow,
|
||||
borrowPerSecondInterestRateSlopeHigh,
|
||||
borrowPerSecondInterestRateBase
|
||||
);
|
||||
|
||||
// 计算新的利息累计因子
|
||||
newSupplyIndex = LendingMath.accrueInterest(supplyIndex, supplyRate, timeElapsed);
|
||||
newBorrowIndex = LendingMath.accrueInterest(borrowIndex, borrowRate, timeElapsed);
|
||||
}
|
||||
|
||||
return (newSupplyIndex, newBorrowIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice 计提利息
|
||||
*/
|
||||
@@ -103,34 +144,8 @@ contract Lending is
|
||||
uint256 timeElapsed = block.timestamp - lastAccrualTime;
|
||||
if (timeElapsed == 0) return;
|
||||
|
||||
// 计算实际的 totalSupply 和 totalBorrow(含利息)
|
||||
// 注意:totalSupplyBase 和 totalBorrowBase 都是正数本金(正数=存款本金,负数=借款本金)
|
||||
// supplyIndex 用于存款,borrowIndex 用于借款
|
||||
uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18;
|
||||
uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18;
|
||||
|
||||
uint64 utilization = LendingMath.getUtilization(totalSupply, totalBorrow);
|
||||
|
||||
// 计算供应利率和借款利率(每秒利率)
|
||||
uint64 supplyRate = LendingMath.getSupplyRate(
|
||||
utilization,
|
||||
supplyKink,
|
||||
supplyPerSecondInterestRateSlopeLow,
|
||||
supplyPerSecondInterestRateSlopeHigh,
|
||||
supplyPerSecondInterestRateBase
|
||||
);
|
||||
|
||||
uint64 borrowRate = LendingMath.getBorrowRate(
|
||||
utilization,
|
||||
borrowKink,
|
||||
borrowPerSecondInterestRateSlopeLow,
|
||||
borrowPerSecondInterestRateSlopeHigh,
|
||||
borrowPerSecondInterestRateBase
|
||||
);
|
||||
|
||||
// 更新利息累计因子(使用每秒利率)
|
||||
supplyIndex = LendingMath.accrueInterest(supplyIndex, supplyRate, timeElapsed);
|
||||
borrowIndex = LendingMath.accrueInterest(borrowIndex, borrowRate, timeElapsed);
|
||||
// 使用辅助函数计算新索引
|
||||
(supplyIndex, borrowIndex) = accruedInterestIndices(timeElapsed);
|
||||
|
||||
lastAccrualTime = block.timestamp;
|
||||
}
|
||||
@@ -323,12 +338,13 @@ contract Lending is
|
||||
AssetConfig memory assetConfig = assetConfigs[asset];
|
||||
uint256 assetPrice = IPriceFeed(assetConfig.priceFeed).getPrice();
|
||||
|
||||
// 计算抵押品价值(USD,8位精度)
|
||||
// 计算抵押品价值(USD,8位精度)- 用于事件记录
|
||||
uint256 assetScale = 10 ** assetConfig.decimals;
|
||||
uint256 collateralValueUSD = (collateralAmount * assetPrice) / assetScale;
|
||||
|
||||
// 应用 liquidationFactor 折扣
|
||||
uint256 discountedValue = (collateralValueUSD * assetConfig.liquidationFactor) / 1e18;
|
||||
// 直接计算折扣后的价值,避免二次除法
|
||||
// discounted = (amount * price * factor) / (scale * 1e18)
|
||||
uint256 discountedValue = (collateralAmount * assetPrice * assetConfig.liquidationFactor) / (assetScale * 1e18);
|
||||
totalCollateralValue += discountedValue;
|
||||
|
||||
// 将抵押品转移到清算库存
|
||||
@@ -410,6 +426,12 @@ contract Lending is
|
||||
) external override nonReentrant whenNotPaused {
|
||||
if (collateralReserves[asset] == 0) revert InsufficientBalance();
|
||||
|
||||
// 检查储备金是否充足(使用实时计算的储备金)
|
||||
int256 currentReserves = getReserves();
|
||||
if (currentReserves >= 0 && uint256(currentReserves) >= targetReserves) {
|
||||
revert NotForSale(); // 储备金充足,无需出售
|
||||
}
|
||||
|
||||
// 计算可购买的抵押品数量
|
||||
uint256 collateralAmount = quoteCollateral(asset, baseAmount);
|
||||
|
||||
@@ -417,15 +439,6 @@ contract Lending is
|
||||
if (collateralAmount < minAmount) revert InsufficientBalance();
|
||||
if (collateralAmount > collateralReserves[asset]) revert InsufficientBalance();
|
||||
|
||||
// 检查储备金是否充足(如果已达到目标,不再出售抵押品)
|
||||
uint256 balance = IERC20(baseToken).balanceOf(address(this));
|
||||
uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18;
|
||||
uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18;
|
||||
int256 currentReserves = int256(balance) - int256(totalSupply) + int256(totalBorrow);
|
||||
if (currentReserves >= 0 && uint256(currentReserves) >= targetReserves) {
|
||||
revert NotForSale(); // 储备金充足,无需出售
|
||||
}
|
||||
|
||||
// 收取清算人支付的资金
|
||||
IERC20(baseToken).safeTransferFrom(msg.sender, address(this), baseAmount);
|
||||
|
||||
@@ -448,23 +461,17 @@ contract Lending is
|
||||
uint256 assetPrice = IPriceFeed(assetConfig.priceFeed).getPrice();
|
||||
uint256 basePrice = IPriceFeed(baseTokenPriceFeed).getPrice();
|
||||
|
||||
// 计算折扣率
|
||||
// discountFactor = storeFrontPriceFactor * (FACTOR_SCALE - liquidationFactor) / FACTOR_SCALE
|
||||
uint256 FACTOR_SCALE = 1e18;
|
||||
uint256 discountFactor = (storeFrontPriceFactor * (FACTOR_SCALE - assetConfig.liquidationFactor)) / FACTOR_SCALE;
|
||||
|
||||
// 计算折扣后的资产价格
|
||||
// assetPriceDiscounted = assetPrice * (FACTOR_SCALE - discountFactor) / FACTOR_SCALE
|
||||
uint256 assetPriceDiscounted = (assetPrice * (FACTOR_SCALE - discountFactor)) / FACTOR_SCALE;
|
||||
|
||||
// 计算可购买的抵押品数量
|
||||
// 公式:(basePrice * baseAmount * assetScale) / (assetPriceDiscounted * baseScale)
|
||||
uint256 baseScale = 10 ** uint256(IERC20Metadata(baseToken).decimals());
|
||||
uint256 assetScale = 10 ** uint256(assetConfig.decimals);
|
||||
|
||||
// 使用中间变量分步计算,避免潜在的溢出
|
||||
// 先计算分子和分母,再进行除法
|
||||
return (basePrice * baseAmount * assetScale) / (assetPriceDiscounted * baseScale);
|
||||
// 折扣因子
|
||||
uint256 discountFactor = (storeFrontPriceFactor * (FACTOR_SCALE - assetConfig.liquidationFactor)) / FACTOR_SCALE;
|
||||
|
||||
// 分子: basePrice * baseAmount * assetScale * FACTOR_SCALE
|
||||
// 分母: assetPrice * (FACTOR_SCALE - discountFactor) * baseScale
|
||||
return (basePrice * baseAmount * assetScale * FACTOR_SCALE) /
|
||||
(assetPrice * (FACTOR_SCALE - discountFactor) * baseScale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,11 +586,15 @@ contract Lending is
|
||||
return collateralReserves[asset];
|
||||
}
|
||||
|
||||
function getReserves() external view override returns (int256) {
|
||||
// 计算实际总供应和总借款(含利息)
|
||||
function getReserves() public view override returns (int256) {
|
||||
// 计算最新的利息索引(不修改状态)
|
||||
uint256 timeElapsed = block.timestamp - lastAccrualTime;
|
||||
(uint256 newSupplyIndex, uint256 newBorrowIndex) = accruedInterestIndices(timeElapsed);
|
||||
|
||||
// 使用最新索引计算实际总供应和总借款(含利息)
|
||||
uint256 balance = IERC20(baseToken).balanceOf(address(this));
|
||||
uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18;
|
||||
uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18;
|
||||
uint256 totalSupply = (uint256(totalSupplyBase) * newSupplyIndex) / 1e18;
|
||||
uint256 totalBorrow = (uint256(totalBorrowBase) * newBorrowIndex) / 1e18;
|
||||
|
||||
// reserves = balance - totalSupply + totalBorrow
|
||||
return int256(balance) - int256(totalSupply) + int256(totalBorrow);
|
||||
@@ -629,10 +640,8 @@ contract Lending is
|
||||
* @notice 提取协议储备金(仅 owner)
|
||||
*/
|
||||
function withdrawReserves(address to, uint256 amount) external override onlyOwner nonReentrant {
|
||||
uint256 balance = IERC20(baseToken).balanceOf(address(this));
|
||||
uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18;
|
||||
uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18;
|
||||
int256 currentReserves = int256(balance) - int256(totalSupply) + int256(totalBorrow);
|
||||
// 使用实时计算的储备金
|
||||
int256 currentReserves = getReserves();
|
||||
|
||||
// 检查储备金是否充足
|
||||
if (currentReserves < 0 || amount > uint256(currentReserves)) {
|
||||
|
||||
Reference in New Issue
Block a user