Files
assetxContracts/contracts/ytLp/core/YTRewardRouter.sol
2025-12-23 14:05:41 +08:00

222 lines
6.3 KiB
Solidity
Raw Permalink 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-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../../interfaces/IYTPoolManager.sol";
import "../../interfaces/IYTVault.sol";
/**
* @title YTRewardRouter
* @notice 用户交互入口
* @dev UUPS可升级合约
*/
contract YTRewardRouter is Initializable, UUPSUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable {
using SafeERC20 for IERC20;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
error Forbidden();
error AlreadyInitialized();
error InvalidAddress();
error InvalidAmount();
error InsufficientOutput();
address public gov;
address public usdy;
address public ytLP;
address public ytPoolManager;
address public ytVault;
event Swap(
address indexed account,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut
);
modifier onlyGov() {
if (msg.sender != gov) revert Forbidden();
_;
}
/**
* @notice 初始化合约
* @param _usdy USDY代币地址
* @param _ytLP ytLP代币地址
* @param _ytPoolManager YTPoolManager地址
* @param _ytVault YTVault地址
*/
function initialize(
address _usdy,
address _ytLP,
address _ytPoolManager,
address _ytVault
) external initializer {
if (_usdy == address(0)) revert InvalidAddress();
if (_ytLP == address(0)) revert InvalidAddress();
if (_ytPoolManager == address(0)) revert InvalidAddress();
if (_ytVault == address(0)) revert InvalidAddress();
__ReentrancyGuard_init();
__UUPSUpgradeable_init();
__Pausable_init();
gov = msg.sender;
usdy = _usdy;
ytLP = _ytLP;
ytPoolManager = _ytPoolManager;
ytVault = _ytVault;
}
/**
* @notice 授权升级仅gov可调用
* @param newImplementation 新实现合约地址
*/
function _authorizeUpgrade(address newImplementation) internal override onlyGov {}
/**
* @notice 暂停合约仅gov可调用
* @dev 暂停后,所有资金流动操作将被禁止
*/
function pause() external onlyGov {
_pause();
}
/**
* @notice 恢复合约仅gov可调用
*/
function unpause() external onlyGov {
_unpause();
}
/**
* @notice 添加流动性
* @param _token YT代币或WUSD地址
* @param _amount 代币数量
* @param _minUsdy 最小USDY数量
* @param _minYtLP 最小ytLP数量
* @return ytLPAmount 获得的ytLP数量
*/
function addLiquidity(
address _token,
uint256 _amount,
uint256 _minUsdy,
uint256 _minYtLP
) external nonReentrant whenNotPaused returns (uint256) {
if (_amount == 0) revert InvalidAmount();
address account = msg.sender;
IERC20(_token).safeTransferFrom(account, address(this), _amount);
IERC20(_token).approve(ytPoolManager, _amount);
uint256 ytLPAmount = IYTPoolManager(ytPoolManager).addLiquidityForAccount(
address(this),
account,
_token,
_amount,
_minUsdy,
_minYtLP
);
return ytLPAmount;
}
/**
* @notice 移除流动性
* @param _tokenOut 输出代币地址
* @param _ytLPAmount ytLP数量
* @param _minOut 最小输出数量
* @param _receiver 接收地址
* @return amountOut 获得的代币数量
*/
function removeLiquidity(
address _tokenOut,
uint256 _ytLPAmount,
uint256 _minOut,
address _receiver
) external nonReentrant whenNotPaused returns (uint256) {
if (_ytLPAmount == 0) revert InvalidAmount();
address account = msg.sender;
uint256 amountOut = IYTPoolManager(ytPoolManager).removeLiquidityForAccount(
account,
_tokenOut,
_ytLPAmount,
_minOut,
_receiver
);
return amountOut;
}
/**
* @notice YT代币互换
* @param _tokenIn 输入代币地址
* @param _tokenOut 输出代币地址
* @param _amountIn 输入数量
* @param _minOut 最小输出数量
* @param _receiver 接收地址
* @return amountOut 获得的代币数量
*/
function swapYT(
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
uint256 _minOut,
address _receiver
) external nonReentrant whenNotPaused returns (uint256) {
if (_amountIn == 0) revert InvalidAmount();
address account = msg.sender;
IERC20(_tokenIn).safeTransferFrom(account, ytVault, _amountIn);
uint256 amountOut = IYTVault(ytVault).swap(_tokenIn, _tokenOut, _receiver);
if (amountOut < _minOut) revert InsufficientOutput();
emit Swap(account, _tokenIn, _tokenOut, _amountIn, amountOut);
return amountOut;
}
/**
* @notice 获取ytLP价格
* @return ytLP价格18位精度
*/
function getYtLPPrice() external view returns (uint256) {
return IYTPoolManager(ytPoolManager).getPrice(true);
}
/**
* @notice 获取账户价值
* @param _account 账户地址
* @return 账户持有的ytLP价值USDY计价
*/
function getAccountValue(address _account) external view returns (uint256) {
uint256 ytLPBalance = IERC20(ytLP).balanceOf(_account);
uint256 ytLPPrice = IYTPoolManager(ytPoolManager).getPrice(true);
return ytLPBalance * ytLPPrice / (10 ** 18);
}
/**
* @dev 预留存储空间,用于未来升级时添加新的状态变量
* 50个slot = 50 * 32 bytes = 1600 bytes
*/
uint256[50] private __gap;
}