change WUSD payment to USDC

This commit is contained in:
2025-12-24 16:41:26 +08:00
parent d2e9377f78
commit e21ee7a5df
160 changed files with 6038 additions and 4050 deletions

View File

@@ -257,7 +257,7 @@ contract YTPoolManager is Initializable, UUPSUpgradeable, ReentrancyGuardUpgrade
function getAumInUsdy(bool _maximise) public view returns (uint256) {
uint256 aum = IYTVault(ytVault).getPoolValue(_maximise);
aum += aumAddition;
aum += aumAddition; // aumAddition是协议额外增加的AUM用来“预留风险缓冲 / 扣除潜在负债”
if (aum > aumDeduction) {
aum -= aumDeduction;
} else {

View File

@@ -3,7 +3,8 @@ pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "../../interfaces/IYTToken.sol";
import "../../interfaces/IYTAssetVault.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
/**
* @title YTPriceFeed
@@ -22,6 +23,7 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
error PriceChangeTooLarge();
error SpreadTooHigh();
error InvalidAddress();
error InvalidChainlinkPrice();
address public gov;
@@ -29,14 +31,13 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
uint256 public constant BASIS_POINTS_DIVISOR = 10000;
uint256 public constant MAX_SPREAD_BASIS_POINTS = 200; // 最大2%价差
// WUSD固定价格
address public wusdAddress;
// WUSD价格来源
address public wusdPriceSource;
address public usdcAddress;
// 价格保护参数
uint256 public maxPriceChangeBps; // 5% 最大价格变动
/// @notice USDC价格Feed
AggregatorV3Interface internal usdcPriceFeed;
// 价差配置(每个代币可以有不同的价差)
mapping(address => uint256) public spreadBasisPoints;
@@ -64,13 +65,31 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
/**
* @notice 初始化合约
*/
function initialize(address _wusdAddress) external initializer {
function initialize(address _usdcAddress, address _usdcPriceFeed) external initializer {
__UUPSUpgradeable_init();
if (_wusdAddress == address(0)) revert InvalidAddress();
wusdAddress = _wusdAddress;
if (_usdcAddress == address(0)) revert InvalidAddress();
usdcAddress = _usdcAddress;
usdcPriceFeed = AggregatorV3Interface(_usdcPriceFeed);
gov = msg.sender;
maxPriceChangeBps = 500; // 5% 最大价格变动
}
/**
* @notice 设置USDC地址
* @param _usdcAddress USDC地址
*/
function setUSDCAddress(address _usdcAddress) external onlyGov {
if (_usdcAddress == address(0)) revert InvalidAddress();
usdcAddress = _usdcAddress;
}
/**
* @notice 设置USDC价格Feed
* @param _usdcPriceFeed USDC价格Feed地址
*/
function setUSDCPriceFeed(address _usdcPriceFeed) external onlyGov {
usdcPriceFeed = AggregatorV3Interface(_usdcPriceFeed);
}
/**
* @notice 授权升级仅gov可调用
@@ -78,14 +97,6 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
*/
function _authorizeUpgrade(address newImplementation) internal override onlyGov {}
/**
* @notice 设置WUSD价格来源YTAssetVault地址
* @param _wusdPriceSource YTAssetVault合约地址
*/
function setWusdPriceSource(address _wusdPriceSource) external onlyGov {
wusdPriceSource = _wusdPriceSource;
}
/**
* @notice 设置keeper权限
* @param _keeper keeper地址
@@ -132,6 +143,30 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
emit SpreadUpdate(_tokens[i], _spreadBasisPoints[i]);
}
}
/**
* @notice 更新并缓存代币价格keeper调用
* @param _token 代币地址
* @return 更新后的价格
*/
function updatePrice(address _token) external onlyKeeper returns (uint256) {
if (_token == usdcAddress) {
return _getUSDCPrice();
}
uint256 oldPrice = lastPrice[_token];
uint256 newPrice = _getRawPrice(_token);
// 价格波动检查
_validatePriceChange(_token, newPrice);
// 更新缓存价格
lastPrice[_token] = newPrice;
emit PriceUpdate(_token, oldPrice, newPrice, block.timestamp);
return newPrice;
}
/**
* @notice 强制更新价格(紧急情况)
@@ -159,8 +194,8 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
* - swap时tokenOut_maximise=true高估输出
*/
function getPrice(address _token, bool _maximise) external view returns (uint256) {
if (_token == wusdAddress) {
return _getWUSDPrice();
if (_token == usdcAddress) {
return _getUSDCPrice();
}
uint256 basePrice = _getRawPrice(_token);
@@ -172,47 +207,31 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
return _applySpread(_token, basePrice, _maximise);
}
/**
* @notice 更新价格并返回由keeper调用
* @param _token 代币地址
* @return 新价格
*/
function updatePrice(address _token) external onlyKeeper returns (uint256) {
if (_token == wusdAddress) {
return _getWUSDPrice();
}
uint256 oldPrice = lastPrice[_token];
uint256 newPrice = _getRawPrice(_token);
// 价格波动检查
_validatePriceChange(_token, newPrice);
lastPrice[_token] = newPrice;
emit PriceUpdate(_token, oldPrice, newPrice, block.timestamp);
return newPrice;
}
/**
* @notice 直接读取YT代币的ytPrice变量
*/
function _getRawPrice(address _token) private view returns (uint256) {
return IYTToken(_token).ytPrice();
return IYTAssetVault(_token).ytPrice();
}
/**
* @notice 从配置的YTAssetVault读取wusdPrice
* @dev 如果未设置wusdPriceSource返回固定价格1.0
* @notice 获取并验证USDC价格从Chainlink
* @return 返回uint256格式的USDC价格精度为1e30
*/
function _getWUSDPrice() private view returns (uint256) {
if (wusdPriceSource == address(0)) {
return PRICE_PRECISION; // 默认1.0
}
return IYTToken(wusdPriceSource).wusdPrice();
function _getUSDCPrice() internal view returns (uint256) {
(
/* uint80 roundId */,
int256 price,
/* uint256 startedAt */,
/* uint256 updatedAt */,
/* uint80 answeredInRound */
) = usdcPriceFeed.latestRoundData();
if (price <= 0) revert InvalidChainlinkPrice();
return uint256(price) * 1e22; // 1e22 = 10^(30-8)
}
/**
* @notice 应用价差
* @param _token 代币地址
@@ -269,12 +288,12 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
uint256 minPrice,
uint256 spread
) {
if (_token == wusdAddress) {
uint256 wusdPrice = _getWUSDPrice();
currentPrice = wusdPrice;
cachedPrice = wusdPrice;
maxPrice = wusdPrice;
minPrice = wusdPrice;
if (_token == usdcAddress) {
uint256 usdcPrice = _getUSDCPrice();
currentPrice = usdcPrice;
cachedPrice = usdcPrice;
maxPrice = usdcPrice;
minPrice = usdcPrice;
spread = 0;
} else {
currentPrice = _getRawPrice(_token);
@@ -289,9 +308,9 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
* @notice 获取最大价格(上浮价差)
*/
function getMaxPrice(address _token) external view returns (uint256) {
if (_token == wusdAddress) {
// WUSD通常不需要价差直接返回原价格
return _getWUSDPrice();
if (_token == usdcAddress) {
// USDC通常不需要价差,直接返回原价格
return _getUSDCPrice();
}
uint256 basePrice = _getRawPrice(_token);
_validatePriceChange(_token, basePrice);
@@ -302,9 +321,9 @@ contract YTPriceFeed is Initializable, UUPSUpgradeable {
* @notice 获取最小价格(下压价差)
*/
function getMinPrice(address _token) external view returns (uint256) {
if (_token == wusdAddress) {
// WUSD通常不需要价差直接返回原价格
return _getWUSDPrice();
if (_token == usdcAddress) {
// USDC通常不需要价差,直接返回原价格
return _getUSDCPrice();
}
uint256 basePrice = _getRawPrice(_token);
_validatePriceChange(_token, basePrice);

View File

@@ -72,7 +72,6 @@ contract YTRewardRouter is Initializable, UUPSUpgradeable, ReentrancyGuardUpgrad
gov = msg.sender;
usdy = _usdy;
ytLP = _ytLP;
ytPoolManager = _ytPoolManager;
@@ -102,7 +101,7 @@ contract YTRewardRouter is Initializable, UUPSUpgradeable, ReentrancyGuardUpgrad
/**
* @notice 添加流动性
* @param _token YT代币或WUSD地址
* @param _token YT代币或USDC地址
* @param _amount 代币数量
* @param _minUsdy 最小USDY数量
* @param _minYtLP 最小ytLP数量

View File

@@ -390,7 +390,7 @@ contract YTVault is Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable {
if (amountOutAfterFees == 0) revert InvalidAmount();
if (poolAmounts[_tokenOut] < amountOutAfterFees) revert InsufficientPool();
// 全局滑点保护
// 全局滑点保护10%
_validateSwapSlippage(amountIn, amountOutAfterFees, priceIn, priceOut);
_increasePoolAmount(_tokenIn, amountIn);
@@ -509,7 +509,7 @@ contract YTVault is Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable {
address _tokenOut,
uint256 _usdyAmount
) private view returns (uint256) {
// 稳定币交换是指两个代币都是稳定币(如 WUSD <-> USDC
// 稳定币交换是指两个代币都是稳定币(如 USDC <-> USDT
bool isStableSwap = stableTokens[_tokenIn] && stableTokens[_tokenOut];
uint256 baseBps = isStableSwap ? stableSwapFeeBasisPoints : swapFeeBasisPoints;
uint256 taxBps = isStableSwap ? stableTaxBasisPoints : taxBasisPoints;

View File

@@ -1,59 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
/**
* @title WUSD
* @notice Wrapped USD - 简单的ERC20代币
*/
contract WUSD is Initializable, ERC20Upgradeable, UUPSUpgradeable, OwnableUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice 初始化合约
* @param _name 代币名称
* @param _symbol 代币符号
*/
function initialize(string memory _name, string memory _symbol) external initializer {
__ERC20_init(_name, _symbol);
__UUPSUpgradeable_init();
__Ownable_init(msg.sender);
}
/**
* @notice 授权升级仅owner可调用
* @param newImplementation 新实现合约地址
*/
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
/**
* @notice 铸造代币
* @param _to 接收地址
* @param _amount 铸造数量
*/
function mint(address _to, uint256 _amount) external onlyOwner {
_mint(_to, _amount);
}
/**
* @notice 销毁代币
* @param _from 销毁地址
* @param _amount 销毁数量
*/
function burn(address _from, uint256 _amount) external onlyOwner {
_burn(_from, _amount);
}
/**
* @dev 预留存储空间,用于未来升级时添加新的状态变量
*/
uint256[50] private __gap;
}