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