Files
assetxContracts/contracts/ytLp/tokens/YTToken.sol
2025-12-18 13:07:35 +08:00

162 lines
5.0 KiB
Solidity
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}
}