// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./LendingStorage.sol"; import "./LendingMath.sol"; import "../interfaces/ILending.sol"; import "../interfaces/IYTLendingPriceFeed.sol"; /** * @title Lending * @notice 借贷池核心合约 */ contract Lending is ILending, LendingStorage, UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /** * @notice 初始化函数 * @param config 市场配置 */ function initialize(Configuration calldata config) external initializer { __UUPSUpgradeable_init(); __Ownable_init(msg.sender); __Pausable_init(); __ReentrancyGuard_init(); // 设置基础配置 baseToken = config.baseToken; lendingPriceSource = config.lendingPriceSource; // 常量:一年的秒数 uint64 SECONDS_PER_YEAR = 365 * 24 * 60 * 60; // 31,536,000 // 设置利率参数 supplyKink = config.supplyKink; supplyPerSecondInterestRateSlopeLow = uint64(config.supplyPerYearInterestRateSlopeLow / SECONDS_PER_YEAR); supplyPerSecondInterestRateSlopeHigh = uint64(config.supplyPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR); supplyPerSecondInterestRateBase = uint64(config.supplyPerYearInterestRateBase / SECONDS_PER_YEAR); borrowKink = config.borrowKink; borrowPerSecondInterestRateSlopeLow = uint64(config.borrowPerYearInterestRateSlopeLow / SECONDS_PER_YEAR); borrowPerSecondInterestRateSlopeHigh = uint64(config.borrowPerYearInterestRateSlopeHigh / SECONDS_PER_YEAR); borrowPerSecondInterestRateBase = uint64(config.borrowPerYearInterestRateBase / SECONDS_PER_YEAR); // 设置其他参数 storeFrontPriceFactor = config.storeFrontPriceFactor; baseBorrowMin = config.baseBorrowMin; targetReserves = config.targetReserves; // 初始化利息累计因子 supplyIndex = 1e18; borrowIndex = 1e18; lastAccrualTime = block.timestamp; // 设置抵押资产配置 for (uint i = 0; i < config.assetConfigs.length; i++) { AssetConfig memory assetConfig = config.assetConfigs[i]; // 验证参数合法性(必须 < 1) if(assetConfig.liquidationFactor >= 1e18) revert InvalidLiquidationFactor(); if(assetConfig.borrowCollateralFactor >= 1e18) revert InvalidBorrowCollateralFactor(); if(assetConfig.liquidateCollateralFactor >= 1e18) revert InvalidLiquidateCollateralFactor(); assetConfigs[assetConfig.asset] = assetConfig; assetList.push(assetConfig.asset); } } function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _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 计提利息 */ function accrueInterest() public { uint256 timeElapsed = block.timestamp - lastAccrualTime; if (timeElapsed == 0) return; // 使用辅助函数计算新索引 (supplyIndex, borrowIndex) = accruedInterestIndices(timeElapsed); lastAccrualTime = block.timestamp; } /** * @notice 存入基础资产 */ function supply(uint256 amount) external override nonReentrant whenNotPaused { accrueInterest(); IERC20(baseToken).transferFrom(msg.sender, address(this), amount); // 获取用户当前本金 UserBasic memory user = userBasic[msg.sender]; int104 oldPrincipal = user.principal; // 计算当前实际余额(含利息) uint256 index = oldPrincipal >= 0 ? supplyIndex : borrowIndex; int256 oldBalance = LendingMath.principalToBalance(oldPrincipal, index); // 计算新余额(增加存款) int256 newBalance = oldBalance + int256(amount); // 转换为新本金(可能从借款变为存款) uint256 newIndex = newBalance >= 0 ? supplyIndex : borrowIndex; int104 newPrincipal = LendingMath.balanceToPrincipal(newBalance, newIndex); // 根据新旧本金,计算还款和存款金额 (uint104 repayAmount, uint104 supplyAmount) = LendingMath.repayAndSupplyAmount(oldPrincipal, newPrincipal); // 更新全局状态 totalBorrowBase -= repayAmount; totalSupplyBase += supplyAmount; // 更新用户本金 userBasic[msg.sender].principal = newPrincipal; emit Supply(msg.sender, msg.sender, amount); } /** * @notice 取出基础资产(如果余额不足会自动借款) * @dev 如果用户余额不足,会自动借款,借款金额为 amount,借款利率为 borrowRate,借款期限为 borrowPeriod */ function withdraw(uint256 amount) external override nonReentrant whenNotPaused { accrueInterest(); // 获取用户当前本金 UserBasic memory user = userBasic[msg.sender]; int104 oldPrincipal = user.principal; // 计算当前实际余额(含利息) uint256 index = oldPrincipal >= 0 ? supplyIndex : borrowIndex; int256 oldBalance = LendingMath.principalToBalance(oldPrincipal, index); // 计算新余额 int256 newBalance = oldBalance - int256(amount); // 转换为新本金 uint256 newIndex = newBalance >= 0 ? supplyIndex : borrowIndex; int104 newPrincipal = LendingMath.balanceToPrincipal(newBalance, newIndex); // 计算提取和借款金额 (uint104 withdrawAmount, uint104 borrowAmount) = LendingMath.withdrawAndBorrowAmount(oldPrincipal, newPrincipal); // 更新全局状态 totalSupplyBase -= withdrawAmount; totalBorrowBase += borrowAmount; // 更新用户本金 userBasic[msg.sender].principal = newPrincipal; // 如果变成负余额(借款),检查抵押品 if (newBalance < 0) { if (uint256(-newBalance) < baseBorrowMin) revert BorrowTooSmall(); if (!_isSolvent(msg.sender)) revert InsufficientCollateral(); } IERC20(baseToken).safeTransfer(msg.sender, amount); emit Withdraw(msg.sender, msg.sender, amount); } /** * @notice 存入抵押品 * @dev 由于不涉及债务计算,存入抵押品反而会让账户更安全,所以不用更新利息因子 */ function supplyCollateral(address asset, uint256 amount) external override nonReentrant whenNotPaused { AssetConfig memory config = assetConfigs[asset]; if (config.asset == address(0)) revert Unauthorized(); uint256 newTotal = userCollateral[msg.sender][asset] + amount; if (newTotal > config.supplyCap) revert SupplyCapExceeded(); IERC20(asset).transferFrom(msg.sender, address(this), amount); userCollateral[msg.sender][asset] += amount; emit SupplyCollateral(msg.sender, msg.sender, asset, amount); } /** * @notice 取出抵押品 */ function withdrawCollateral(address asset, uint256 amount) external override nonReentrant whenNotPaused { accrueInterest(); if (userCollateral[msg.sender][asset] < amount) revert InsufficientBalance(); userCollateral[msg.sender][asset] -= amount; // 检查是否仍有足够的抵押品(如果有债务) int104 principal = userBasic[msg.sender].principal; if (principal < 0) { if (!_isSolvent(msg.sender)) revert InsufficientCollateral(); } IERC20(asset).safeTransfer(msg.sender, amount); emit WithdrawCollateral(msg.sender, msg.sender, asset, amount); } /** * @notice 清算不良债务(内部实现) * @dev 当用户抵押品由于乘以liquidateCollateralFactor后,小于债务价值时,会进行清算,清算后,如果实际抵押品价值乘以liquidateCollateralFactor大于债务价值,则将差额部分作为用户本金(本金以baseToken显示),否则将差额部分作为坏账,由协议承担 */ function _absorbInternal(address absorber, address borrower) internal { if (!isLiquidatable(borrower)) revert NotLiquidatable(); // 获取用户当前本金 UserBasic memory user = userBasic[borrower]; int104 oldPrincipal = user.principal; // 计算当前实际余额(含利息累计的债务) int256 oldBalance = LendingMath.principalToBalance(oldPrincipal, borrowIndex); if (oldBalance >= 0) revert NotLiquidatable(); // 计算所有抵押品的总价值(按 liquidationFactor 折扣) uint256 basePrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(baseToken); uint256 totalCollateralValue = 0; for (uint i = 0; i < assetList.length; i++) { address asset = assetList[i]; uint256 collateralAmount = userCollateral[borrower][asset]; if (collateralAmount > 0) { AssetConfig memory assetConfig = assetConfigs[asset]; uint256 assetPrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset); // 计算抵押品价值-用于事件记录 uint256 assetScale = 10 ** assetConfig.decimals; uint256 collateralValueUSD = (collateralAmount * assetPrice) / assetScale; // 直接计算折扣后的价值,避免二次除法 // discounted = (amount * price * factor) / (scale * 1e18) uint256 discountedValue = (collateralAmount * assetPrice * assetConfig.liquidationFactor) / (assetScale * 1e18); totalCollateralValue += discountedValue; // 将抵押品转移到清算库存 userCollateral[borrower][asset] = 0; collateralReserves[asset] += collateralAmount; // 发射抵押品吸收事件 emit AbsorbCollateral(absorber, borrower, asset, collateralAmount, collateralValueUSD); } } // 将抵押品价值转换为 baseToken 数量 uint256 baseScale = 10 ** IERC20Metadata(baseToken).decimals(); uint256 collateralInBase = (totalCollateralValue * baseScale) / basePrice; // 计算新余额:oldBalance(负数)+ 抵押品价值 int256 newBalance = oldBalance + int256(collateralInBase); // 如果新余额仍为负,强制归零(坏账由协议承担) if (newBalance < 0) { newBalance = 0; } // 转换为新本金 int104 newPrincipal = LendingMath.balanceToPrincipal(newBalance, supplyIndex); // 更新用户本金 userBasic[borrower].principal = newPrincipal; // 计算偿还和供应金额 (uint104 repayAmount, uint104 supplyAmount) = LendingMath.repayAndSupplyAmount(oldPrincipal, newPrincipal); // 更新全局状态(储备金通过减少 totalBorrowBase 和增加 totalSupplyBase 来承担坏账) totalSupplyBase += supplyAmount; totalBorrowBase -= repayAmount; // 计算协议承担的坏账部分 // 坏账 = 用户债务 - 抵押品价值(当抵押品不足时) uint256 basePaidOut = 0; if (int256(collateralInBase) < -oldBalance) { // 抵押品不足以覆盖债务,差额由协议储备金承担 basePaidOut = uint256(-oldBalance) - collateralInBase; } // 如果 collateralInBase >= -oldBalance,说明抵押品足够,无坏账 uint256 valueOfBasePaidOut = (basePaidOut * basePrice) / baseScale; // 发射债务吸收事件 emit AbsorbDebt(absorber, borrower, basePaidOut, valueOfBasePaidOut); } /** * @notice 清算不良债务(单个) */ function absorb(address borrower) external override nonReentrant whenNotPaused { accrueInterest(); _absorbInternal(msg.sender, borrower); } /** * @notice 批量清算不良债务 */ function absorbMultiple(address absorber, address[] calldata accounts) external override nonReentrant whenNotPaused { accrueInterest(); for (uint i = 0; i < accounts.length; ) { _absorbInternal(absorber, accounts[i]); unchecked { i++; } } } /** * @notice 购买清算后的抵押品 * @dev 自动限制购买量到可用储备,只收取实际需要的费用 */ function buyCollateral( address asset, uint256 minAmount, uint256 baseAmount, address recipient ) external override nonReentrant whenNotPaused { if (collateralReserves[asset] == 0) revert InsufficientBalance(); // 检查储备金是否充足(使用实时计算的储备金) int256 currentReserves = getReserves(); if (currentReserves >= 0 && uint256(currentReserves) >= targetReserves) { revert NotForSale(); // 储备金充足,无需出售 } // 计算可购买的抵押品数量(基于用户愿意支付的 baseAmount) uint256 collateralAmount = quoteCollateral(asset, baseAmount); // 自动限制到可用储备量 // 这样可以防止价格波动导致交易失败 if (collateralAmount > collateralReserves[asset]) { collateralAmount = collateralReserves[asset]; } // 滑点保护:确保购买量不低于用户的最小期望 if (collateralAmount < minAmount) revert InsufficientBalance(); // 根据实际购买量计算需要支付的金额(而非固定的 baseAmount) // 这样如果购买量被限制,用户只需支付相应的费用 uint256 actualBaseAmount = quoteBaseAmount(asset, collateralAmount); // 收取实际需要的资金 IERC20(baseToken).transferFrom(msg.sender, address(this), actualBaseAmount); // 抵押品出库 collateralReserves[asset] -= collateralAmount; // 转账抵押品到指定接收人 IERC20(asset).safeTransfer(recipient, collateralAmount); // 注意:收入会自动体现在 getReserves() 中,因为 balance 增加了 emit BuyCollateral(msg.sender, asset, actualBaseAmount, collateralAmount); } /** * @notice 计算购买指定数量抵押品需要支付的 baseToken 数量(反向计算) * @param asset 抵押品地址 * @param collateralAmount 要购买的抵押品数量 * @return 需要支付的 baseToken 数量 */ function quoteBaseAmount(address asset, uint256 collateralAmount) internal view returns (uint256) { AssetConfig memory assetConfig = assetConfigs[asset]; uint256 assetPrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset); uint256 basePrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(baseToken); uint256 FACTOR_SCALE = 1e18; uint256 baseScale = 10 ** uint256(IERC20Metadata(baseToken).decimals()); uint256 assetScale = 10 ** uint256(assetConfig.decimals); // 计算折扣因子 uint256 discountFactor = (storeFrontPriceFactor * (FACTOR_SCALE - assetConfig.liquidationFactor)) / FACTOR_SCALE; // 计算折扣后的资产价格 uint256 effectiveAssetPrice = (assetPrice * (FACTOR_SCALE - discountFactor)) / FACTOR_SCALE; // 反向计算:baseAmount = (collateralAmount * effectiveAssetPrice * baseScale) / (basePrice * assetScale) if (baseScale == assetScale) { return (collateralAmount * effectiveAssetPrice) / basePrice; } else { uint256 adjustedAmount = (collateralAmount * baseScale) / assetScale; return (adjustedAmount * effectiveAssetPrice) / basePrice; } } /** * @notice 计算支付指定baseAmount可购买的抵押品数量 * @dev 重新设计以避免在 1e30 价格精度下溢出 */ function quoteCollateral(address asset, uint256 baseAmount) public view override returns (uint256) { AssetConfig memory assetConfig = assetConfigs[asset]; uint256 assetPrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset); uint256 basePrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(baseToken); uint256 FACTOR_SCALE = 1e18; uint256 baseScale = 10 ** uint256(IERC20Metadata(baseToken).decimals()); uint256 assetScale = 10 ** uint256(assetConfig.decimals); // 计算折扣因子 uint256 discountFactor = (storeFrontPriceFactor * (FACTOR_SCALE - assetConfig.liquidationFactor)) / FACTOR_SCALE; // 计算折扣后的资产价格 (保持 1e30 精度) uint256 effectiveAssetPrice = (assetPrice * (FACTOR_SCALE - discountFactor)) / FACTOR_SCALE; // 为了避免溢出,我们需要重新排列计算: // result = (basePrice * baseAmount * assetScale) / (effectiveAssetPrice * baseScale) // // 由于所有价格都是 1e30 精度,我们可以先约简价格: // priceRatio = basePrice / effectiveAssetPrice (保持精度) // result = (baseAmount * priceRatio * assetScale) / (1e30 * baseScale) // // 但为了避免精度损失,我们分步计算: // step1 = baseAmount * assetScale / baseScale (token amount conversion) // step2 = step1 * basePrice / effectiveAssetPrice (price conversion) // 如果 baseScale 和 assetScale 相同(都是18),可以简化 if (baseScale == assetScale) { // result = baseAmount * basePrice / effectiveAssetPrice return (baseAmount * basePrice) / effectiveAssetPrice; } else { // 一般情况:分步计算避免溢出 uint256 adjustedAmount = (baseAmount * assetScale) / baseScale; return (adjustedAmount * basePrice) / effectiveAssetPrice; } } /** * @notice 检查账户偿付能力 */ function _isSolvent(address account) internal view returns (bool) { int104 principal = userBasic[account].principal; if (principal >= 0) return true; // 计算实际债务(含利息)- 使用 borrowIndex int256 balance = LendingMath.principalToBalance(principal, borrowIndex); uint256 debt = uint256(-balance); // 将 debt 转换为美元价值(使用 baseToken 价格) uint256 basePrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(baseToken); uint256 baseDecimals = IERC20Metadata(baseToken).decimals(); uint256 debtValue = (debt * basePrice) / (10 ** baseDecimals); // 计算借款能力(抵押品价值已经在 _getCollateralValue 中应用了借款系数) uint256 borrowCapacity = _getCollateralValue(account); // 比较:借款能力 >= 债务价值 return borrowCapacity >= debtValue; } /** * @notice 计算账户抵押品总价值 */ function _getCollateralValue(address account) internal view returns (uint256) { uint256 totalValue = 0; for (uint i = 0; i < assetList.length; i++) { address asset = assetList[i]; uint256 amount = userCollateral[account][asset]; if (amount > 0) { AssetConfig memory config = assetConfigs[asset]; uint256 price = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset); uint256 value = LendingMath.getCollateralValue(amount, price, config.decimals); totalValue += (value * config.borrowCollateralFactor) / 1e18; } } return totalValue; } // ========== View Functions ========== function getBalance(address account) external view override returns (int256) { int104 principal = userBasic[account].principal; // 使用 supplyIndex 计算实际余额(含利息) return LendingMath.principalToBalance(principal, supplyIndex); } function supplyBalanceOf(address account) external view override returns (uint256) { int104 principal = userBasic[account].principal; if (principal <= 0) return 0; // 只返回正余额(存款) return uint256(LendingMath.principalToBalance(principal, supplyIndex)); } function borrowBalanceOf(address account) external view override returns (uint256) { int104 principal = userBasic[account].principal; if (principal >= 0) return 0; // 只返回负余额(借款),转为正数 int256 balance = LendingMath.principalToBalance(principal, borrowIndex); return uint256(-balance); } function getCollateral(address account, address asset) external view override returns (uint256) { return userCollateral[account][asset]; } function isLiquidatable(address account) public view override returns (bool) { int104 principal = userBasic[account].principal; if (principal >= 0) return false; // 计算实际债务(含利息) int256 balance = LendingMath.principalToBalance(principal, borrowIndex); uint256 debt = uint256(-balance); // 将 debt 转换为美元价值(使用 baseToken 价格和 price feed 精度) uint256 basePrice = IYTLendingPriceFeed(lendingPriceSource).getPrice(baseToken); uint256 baseDecimals = IERC20Metadata(baseToken).decimals(); uint256 debtValue = (debt * basePrice) / (10 ** baseDecimals); // 计算抵押品总价值(清算阈值) uint256 collateralValue = 0; for (uint i = 0; i < assetList.length; i++) { address asset = assetList[i]; uint256 amount = userCollateral[account][asset]; if (amount > 0) { AssetConfig memory config = assetConfigs[asset]; uint256 price = IYTLendingPriceFeed(lendingPriceSource).getPrice(asset); uint256 value = LendingMath.getCollateralValue(amount, price, config.decimals); collateralValue += (value * config.liquidateCollateralFactor) / 1e18; } } // 比较:债务价值 > 抵押品清算阈值价值 return debtValue > collateralValue; } function getTotalSupply() external view returns (uint256) { return (uint256(totalSupplyBase) * supplyIndex) / 1e18; } function getTotalBorrow() external view returns (uint256) { return (uint256(totalBorrowBase) * borrowIndex) / 1e18; } function getCollateralReserves(address asset) external view override returns (uint256) { return collateralReserves[asset]; } 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) * newSupplyIndex) / 1e18; uint256 totalBorrow = (uint256(totalBorrowBase) * newBorrowIndex) / 1e18; // reserves = balance - totalSupply + totalBorrow return int256(balance) - int256(totalSupply) + int256(totalBorrow); } function getUtilization() external view override returns (uint256) { uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18; uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18; return LendingMath.getUtilization(totalSupply, totalBorrow); } function getSupplyRate() external view override returns (uint64) { uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18; uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18; uint64 utilization = LendingMath.getUtilization(totalSupply, totalBorrow); uint64 perSecondRate = LendingMath.getSupplyRate( utilization, supplyKink, supplyPerSecondInterestRateSlopeLow, supplyPerSecondInterestRateSlopeHigh, supplyPerSecondInterestRateBase ); // 转换为年化利率(APY) return perSecondRate * 31536000; // SECONDS_PER_YEAR } function getBorrowRate() external view override returns (uint64) { uint256 totalSupply = (uint256(totalSupplyBase) * supplyIndex) / 1e18; uint256 totalBorrow = (uint256(totalBorrowBase) * borrowIndex) / 1e18; uint64 utilization = LendingMath.getUtilization(totalSupply, totalBorrow); uint64 perSecondRate = LendingMath.getBorrowRate( utilization, borrowKink, borrowPerSecondInterestRateSlopeLow, borrowPerSecondInterestRateSlopeHigh, borrowPerSecondInterestRateBase ); // 转换为年化利率(APY) return perSecondRate * 31536000; // SECONDS_PER_YEAR } /** * @notice 提取协议储备金(仅 owner) */ function withdrawReserves(address to, uint256 amount) external override onlyOwner nonReentrant { // 使用实时计算的储备金 int256 currentReserves = getReserves(); // 检查储备金是否充足 if (currentReserves < 0 || amount > uint256(currentReserves)) { revert InsufficientReserves(); } // 转账储备金 IERC20(baseToken).safeTransfer(to, amount); emit WithdrawReserves(to, amount); } /** * @dev 预留存储空间,用于未来升级时添加新的状态变量 * 50个slot = 50 * 32 bytes = 1600 bytes */ uint256[50] private __gap; }