change WUSD payment to USDC
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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数量
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user