2025-12-24 16:41:26 +08:00
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
pragma solidity ^0.8.0;
|
|
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
|
import "../interfaces/IYTAssetVault.sol";
|
|
|
|
|
|
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
|
|
|
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
|
|
|
|
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
|
2025-12-24 16:41:26 +08:00
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
|
contract LendingPriceFeed is OwnableUpgradeable, UUPSUpgradeable {
|
|
|
|
|
|
address public usdcAddress;
|
|
|
|
|
|
AggregatorV3Interface internal usdcPriceFeed;
|
2026-01-12 14:33:16 +08:00
|
|
|
|
|
|
|
|
|
|
/// @notice 价格过期阈值(秒)
|
|
|
|
|
|
uint256 public priceStalenesThreshold;
|
2025-12-24 16:41:26 +08:00
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
|
error InvalidUsdcAddress();
|
|
|
|
|
|
error InvalidUsdcPriceFeedAddress();
|
|
|
|
|
|
error InvalidChainlinkPrice();
|
2026-01-12 14:33:16 +08:00
|
|
|
|
error StalePrice();
|
2025-12-26 13:23:50 +08:00
|
|
|
|
|
|
|
|
|
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
_disableInitializers();
|
2025-12-24 16:41:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
|
function initialize(address _usdcAddress, address _usdcPriceFeed) external initializer {
|
|
|
|
|
|
__UUPSUpgradeable_init();
|
|
|
|
|
|
__Ownable_init(msg.sender);
|
|
|
|
|
|
if (_usdcAddress == address(0)) revert InvalidUsdcAddress();
|
|
|
|
|
|
if (_usdcPriceFeed == address(0)) revert InvalidUsdcPriceFeedAddress();
|
|
|
|
|
|
usdcAddress = _usdcAddress;
|
|
|
|
|
|
usdcPriceFeed = AggregatorV3Interface(_usdcPriceFeed);
|
2026-01-12 14:33:16 +08:00
|
|
|
|
priceStalenesThreshold = 3600; // 默认1小时
|
2025-12-24 16:41:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
|
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
|
|
|
|
|
|
|
|
|
|
|
|
function setUsdcAddress(address _usdcAddress) external onlyOwner {
|
|
|
|
|
|
if (_usdcAddress == address(0)) revert InvalidUsdcAddress();
|
|
|
|
|
|
usdcAddress = _usdcAddress;
|
2025-12-24 16:41:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 14:33:16 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @notice 设置价格过期阈值
|
|
|
|
|
|
* @param _threshold 阈值(秒),例如:3600 = 1小时,86400 = 24小时
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setPriceStalenessThreshold(uint256 _threshold) external onlyOwner {
|
|
|
|
|
|
require(_threshold > 0 && _threshold <= 7 days, "Invalid threshold");
|
|
|
|
|
|
priceStalenesThreshold = _threshold;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
|
function getPrice(address _token) external view returns (uint256) {
|
2025-12-26 13:23:50 +08:00
|
|
|
|
if (_token == usdcAddress) {
|
|
|
|
|
|
return _getUSDCPrice();
|
2025-12-24 16:41:26 +08:00
|
|
|
|
}
|
2025-12-26 13:23:50 +08:00
|
|
|
|
return IYTAssetVault(_token).ytPrice();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function _getUSDCPrice() internal view returns (uint256) {
|
|
|
|
|
|
(
|
2026-01-12 14:33:16 +08:00
|
|
|
|
uint80 roundId,
|
2025-12-26 13:23:50 +08:00
|
|
|
|
int256 price,
|
|
|
|
|
|
/* uint256 startedAt */,
|
2026-01-12 14:33:16 +08:00
|
|
|
|
uint256 updatedAt,
|
|
|
|
|
|
uint80 answeredInRound
|
2025-12-26 13:23:50 +08:00
|
|
|
|
) = usdcPriceFeed.latestRoundData();
|
|
|
|
|
|
|
2026-01-12 14:33:16 +08:00
|
|
|
|
// 价格有效性检查
|
2025-12-26 13:23:50 +08:00
|
|
|
|
if (price <= 0) revert InvalidChainlinkPrice();
|
|
|
|
|
|
|
2026-01-12 14:33:16 +08:00
|
|
|
|
// 新鲜度检查:确保价格数据不过期
|
|
|
|
|
|
if (updatedAt == 0) revert StalePrice();
|
|
|
|
|
|
if (answeredInRound < roundId) revert StalePrice();
|
|
|
|
|
|
if (block.timestamp - updatedAt > priceStalenesThreshold) revert StalePrice();
|
|
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
|
return uint256(price) * 1e22; // 1e22 = 10^(30-8)
|
2025-12-24 16:41:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|