update lending script

This commit is contained in:
2025-12-22 14:12:50 +08:00
parent 682552bfe6
commit 0024e7adb1
25 changed files with 797 additions and 1108 deletions

View File

@@ -86,21 +86,12 @@ contract Lending is
}
}
/**
* @dev 授权升级函数 - 只有 owner 可以升级
*/
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
/**
* @notice 暂停合约
*/
function pause() external onlyOwner {
_pause();
}
/**
* @notice 恢复合约
*/
function unpause() external onlyOwner {
_unpause();
}
@@ -527,7 +518,7 @@ contract Lending is
return LendingMath.principalToBalance(principal, supplyIndex);
}
function balanceOf(address account) external view override returns (uint256) {
function supplyBalanceOf(address account) external view override returns (uint256) {
int104 principal = userBasic[account].principal;
if (principal <= 0) return 0;
// 只返回正余额(存款)

View File

@@ -5,10 +5,6 @@ import "@openzeppelin/contracts/access/Ownable.sol";
import "./Lending.sol";
import "./LendingConfiguration.sol";
/**
* @title LendingFactory
* @notice 工厂合约 - 用于部署新的 Lending 实现
*/
contract LendingFactory is LendingConfiguration, Ownable {
constructor() Ownable(msg.sender) {}

View File

@@ -6,25 +6,15 @@ pragma solidity ^0.8.0;
* @notice 借贷池核心接口
*/
interface ILending {
// ========== Events ==========
event Supply(address indexed from, address indexed dst, uint256 amount);
event Withdraw(address indexed src, address indexed to, uint256 amount);
event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint256 amount);
event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint256 amount);
/// @notice 清算债务事件
event AbsorbDebt(address indexed absorber, address indexed borrower, uint256 basePaidOut, uint256 usdValue);
/// @notice 清算抵押品事件
event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint256 collateralAbsorbed, uint256 usdValue);
event BuyCollateral(address indexed buyer, address indexed asset, uint256 baseAmount, uint256 collateralAmount);
/// @notice 储备金提取事件
event WithdrawReserves(address indexed to, uint256 amount);
// ========== Errors ==========
error Unauthorized();
error InsufficientBalance();
error InsufficientCollateral();
@@ -37,144 +27,25 @@ interface ILending {
error InsufficientReserves();
error NotForSale();
// ========== Core Functions ==========
/**
* @notice 存入基础资产
* @param amount 存入金额
*/
function supply(uint256 amount) external;
/**
* @notice 取出基础资产
* @param amount 取出金额
*/
function withdraw(uint256 amount) external;
/**
* @notice 存入抵押品
* @param asset 抵押品地址
* @param amount 抵押品数量
*/
function supplyCollateral(address asset, uint256 amount) external;
/**
* @notice 取出抵押品
* @param asset 抵押品地址
* @param amount 抵押品数量
*/
function withdrawCollateral(address asset, uint256 amount) external;
/**
* @notice 借款(通过取出超过存款的基础资产实现)
* @param amount 借款金额
*/
function borrow(uint256 amount) external;
/**
* @notice 清算不良债务(单个)
* @param borrower 待清算的借款人地址
*/
function absorb(address borrower) external;
/**
* @notice 批量清算不良债务
* @param absorber 清算发起人地址
* @param accounts 待清算的借款人地址数组
*/
function absorbMultiple(address absorber, address[] calldata accounts) external;
/**
* @notice 购买清算后的抵押品
* @param asset 抵押品地址
* @param minAmount 最小购买量
* @param baseAmount 支付的基础资产数量
* @param recipient 接收抵押品的地址
*/
function buyCollateral(address asset, uint256 minAmount, uint256 baseAmount, address recipient) external;
// ========== View Functions ==========
/**
* @notice 获取用户基础资产余额
* @param account 用户地址
* @return 余额(正数=存款,负数=借款)
*/
function getBalance(address account) external view returns (int256);
/**
* @notice 获取用户抵押品余额
* @param account 用户地址
* @param asset 抵押品地址
* @return 抵押品数量
*/
function getCollateral(address account, address asset) external view returns (uint256);
/**
* @notice 检查账户是否可被清算
* @param account 用户地址
* @return 是否可清算
*/
function isLiquidatable(address account) external view returns (bool);
/**
* @notice 获取当前供应利率
* @return 供应利率 (年化scaled by 1e18)
*/
function getSupplyRate() external view returns (uint64);
/**
* @notice 获取当前借款利率
* @return 借款利率 (年化scaled by 1e18)
*/
function getBorrowRate() external view returns (uint64);
/**
* @notice 获取用户存款余额只返回正数部分ERC20兼容
* @param account 用户地址
* @return 存款余额
*/
function balanceOf(address account) external view returns (uint256);
/**
* @notice 获取用户借款余额(只返回债务部分)
* @param account 用户地址
* @return 借款余额
*/
function supplyBalanceOf(address account) external view returns (uint256);
function borrowBalanceOf(address account) external view returns (uint256);
/**
* @notice 计算支付指定baseAmount可购买的抵押品数量
* @param asset 抵押品地址
* @param baseAmount 支付的基础资产数量
* @return 可购买的抵押品数量
*/
function quoteCollateral(address asset, uint256 baseAmount) external view returns (uint256);
/**
* @notice 获取协议储备金
* @return 储备金余额(可能为负)
*/
function getReserves() external view returns (int256);
/**
* @notice 获取抵押品库存
* @param asset 抵押品地址
* @return 库存数量
*/
function getCollateralReserves(address asset) external view returns (uint256);
/**
* @notice 获取市场利用率
* @return 利用率scaled by 1e18
*/
function getUtilization() external view returns (uint256);
/**
* @notice 提取协议储备金(仅 owner
* @param to 接收地址
* @param amount 提取数量
*/
function withdrawReserves(address to, uint256 amount) external;
}

View File

@@ -6,16 +6,7 @@ pragma solidity ^0.8.0;
* @notice 价格预言机接口
*/
interface IPriceFeed {
/**
* @notice 获取资产价格
* @return price 价格 (scaled by 1e8)
*/
function getPrice() external view returns (uint256 price);
/**
* @notice 获取价格精度
* @return 价格小数位数
*/
function decimals() external view returns (uint8);
}

View File

@@ -1,161 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title YTToken
* @notice YT代币示例实现Yield Token
* @dev 展示如何实现价格接口供YTPriceFeed读取
*/
contract YTToken is ERC20, Ownable {
error NotUpdater();
error InvalidUpdater();
error IntervalTooLong();
error UpdateTooFrequent();
error InvalidYield();
error InvalidAmount();
error InsufficientAssets();
uint256 public constant PRICE_PRECISION = 10 ** 30;
uint256 public totalAssets;
uint256 public accumulatedYield;
// 价格变量
uint256 public assetPrice;
uint256 public lastPriceUpdate;
// 价格更新控制
address public priceUpdater;
uint256 public minUpdateInterval = 5 minutes; // 最小更新间隔
event PriceUpdated(uint256 oldPrice, uint256 newPrice, uint256 timestamp);
event YieldAccumulated(uint256 amount, uint256 timestamp);
event PriceUpdaterSet(address indexed updater);
event MinUpdateIntervalSet(uint256 interval);
modifier onlyPriceUpdater() {
if (msg.sender != priceUpdater && msg.sender != owner()) revert NotUpdater();
_;
}
constructor(
string memory name,
string memory symbol,
address _priceUpdater
) ERC20(name, symbol) Ownable(msg.sender) {
assetPrice = PRICE_PRECISION; // 初始价格为1
lastPriceUpdate = block.timestamp;
priceUpdater = _priceUpdater;
}
/**
* @notice 设置价格更新者
*/
function setPriceUpdater(address _updater) external onlyOwner {
if (_updater == address(0)) revert InvalidUpdater();
priceUpdater = _updater;
emit PriceUpdaterSet(_updater);
}
/**
* @notice 设置最小更新间隔
*/
function setMinUpdateInterval(uint256 _interval) external onlyOwner {
if (_interval > 1 hours) revert IntervalTooLong();
minUpdateInterval = _interval;
emit MinUpdateIntervalSet(_interval);
}
/**
* @notice 更新代币价格
* @dev 只能由授权的updater调用有最小时间间隔限制
*/
function updatePrice() public onlyPriceUpdater {
if (block.timestamp < lastPriceUpdate + minUpdateInterval) revert UpdateTooFrequent();
uint256 oldPrice = assetPrice;
uint256 supply = totalSupply();
if (supply == 0) {
assetPrice = PRICE_PRECISION;
} else {
uint256 totalValue = totalAssets + accumulatedYield;
// 计算每个token对应的USDC价值18位精度
uint256 usdcPerToken = totalValue * 1e18 / supply;
// 转换为30位精度的价格
assetPrice = usdcPerToken * PRICE_PRECISION / 1e18;
}
lastPriceUpdate = block.timestamp;
emit PriceUpdated(oldPrice, assetPrice, block.timestamp);
}
/**
* @notice 累积收益并更新价格
* @dev 当从收益策略中收到新收益时调用
*/
function updateYield(uint256 _newYield) external onlyPriceUpdater {
if (_newYield == 0) revert InvalidYield();
accumulatedYield += _newYield;
emit YieldAccumulated(_newYield, block.timestamp);
// 收益更新后立即更新价格
if (block.timestamp >= lastPriceUpdate + minUpdateInterval) {
uint256 oldPrice = assetPrice;
uint256 supply = totalSupply();
if (supply > 0) {
uint256 totalValue = totalAssets + accumulatedYield;
uint256 usdcPerToken = totalValue * 1e18 / supply;
assetPrice = usdcPerToken * PRICE_PRECISION / 1e18;
}
lastPriceUpdate = block.timestamp;
emit PriceUpdated(oldPrice, assetPrice, block.timestamp);
}
}
/**
* @notice 存入资产(模拟)
* @dev 实际实现中应该处理真实的USDC存款
*/
function deposit(uint256 _amount) external onlyOwner {
if (_amount == 0) revert InvalidAmount();
totalAssets += _amount;
_mint(msg.sender, _amount);
}
/**
* @notice 提取资产(模拟)
* @dev 实际实现中应该处理真实的USDC提款
*/
function withdraw(uint256 _amount) external onlyOwner {
if (_amount == 0) revert InvalidAmount();
if (totalAssets < _amount) revert InsufficientAssets();
totalAssets -= _amount;
_burn(msg.sender, _amount);
}
/**
* @notice 获取当前价格信息
*/
function getPriceInfo() external view returns (
uint256 price,
uint256 lastUpdate,
uint256 timeSinceUpdate,
uint256 totalVal
) {
price = assetPrice;
lastUpdate = lastPriceUpdate;
timeSinceUpdate = block.timestamp - lastPriceUpdate;
totalVal = totalAssets + accumulatedYield;
}
}