2025-12-18 13:07:35 +08:00
|
|
|
// 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/utils/ReentrancyGuardUpgradeable.sol";
|
|
|
|
|
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
|
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
2025-12-24 16:41:26 +08:00
|
|
|
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
2025-12-18 13:07:35 +08:00
|
|
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
2025-12-24 16:41:26 +08:00
|
|
|
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
contract YTAssetVault is
|
|
|
|
|
Initializable,
|
|
|
|
|
ERC20Upgradeable,
|
|
|
|
|
UUPSUpgradeable,
|
|
|
|
|
ReentrancyGuardUpgradeable,
|
|
|
|
|
PausableUpgradeable
|
|
|
|
|
{
|
|
|
|
|
using SafeERC20 for IERC20;
|
|
|
|
|
|
2025-12-23 14:05:41 +08:00
|
|
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
|
|
|
constructor() {
|
|
|
|
|
_disableInitializers();
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-18 13:07:35 +08:00
|
|
|
error Forbidden();
|
|
|
|
|
error HardCapExceeded();
|
|
|
|
|
error InvalidAmount();
|
|
|
|
|
error InvalidHardCap();
|
|
|
|
|
error InvalidPrice();
|
2025-12-24 16:41:26 +08:00
|
|
|
error InsufficientUSDC();
|
2025-12-18 13:07:35 +08:00
|
|
|
error InsufficientYTA();
|
|
|
|
|
error StillInLockPeriod();
|
2025-12-19 13:26:49 +08:00
|
|
|
error RequestNotFound();
|
|
|
|
|
error RequestAlreadyProcessed();
|
|
|
|
|
error InvalidBatchSize();
|
2025-12-24 16:41:26 +08:00
|
|
|
error InvalidPriceFeed();
|
|
|
|
|
error InvalidChainlinkPrice();
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
address public factory;
|
|
|
|
|
address public manager;
|
|
|
|
|
|
|
|
|
|
uint256 public hardCap;
|
|
|
|
|
uint256 public managedAssets;
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
address public usdcAddress;
|
|
|
|
|
uint8 public usdcDecimals;
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
uint256 public ytPrice;
|
|
|
|
|
uint256 public constant PRICE_PRECISION = 1e30;
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
uint256 public constant CHAINLINK_PRICE_PRECISION = 1e8;
|
|
|
|
|
|
2025-12-18 13:07:35 +08:00
|
|
|
uint256 public nextRedemptionTime;
|
2025-12-24 16:41:26 +08:00
|
|
|
AggregatorV3Interface internal usdcPriceFeed;
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-19 13:26:49 +08:00
|
|
|
struct WithdrawRequest {
|
2025-12-25 13:29:35 +08:00
|
|
|
address user;
|
|
|
|
|
uint256 ytAmount;
|
|
|
|
|
uint256 usdcAmount;
|
|
|
|
|
uint256 requestTime;
|
|
|
|
|
uint256 queueIndex;
|
|
|
|
|
bool processed;
|
2025-12-19 13:26:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mapping(uint256 => WithdrawRequest) public withdrawRequests;
|
|
|
|
|
mapping(address => uint256[]) private userRequestIds;
|
|
|
|
|
|
|
|
|
|
uint256 public requestIdCounter;
|
|
|
|
|
|
|
|
|
|
uint256 public processedUpToIndex;
|
|
|
|
|
|
|
|
|
|
uint256 public pendingRequestsCount;
|
|
|
|
|
|
2025-12-18 13:07:35 +08:00
|
|
|
event HardCapSet(uint256 newHardCap);
|
|
|
|
|
event ManagerSet(address indexed newManager);
|
|
|
|
|
event AssetsWithdrawn(address indexed to, uint256 amount);
|
|
|
|
|
event AssetsDeposited(uint256 amount);
|
2025-12-24 16:41:26 +08:00
|
|
|
event PriceUpdated(uint256 ytPrice, uint256 timestamp);
|
|
|
|
|
event Buy(address indexed user, uint256 usdcAmount, uint256 ytAmount);
|
|
|
|
|
event Sell(address indexed user, uint256 ytAmount, uint256 usdcAmount);
|
2025-12-18 13:07:35 +08:00
|
|
|
event NextRedemptionTimeSet(uint256 newRedemptionTime);
|
2025-12-24 16:41:26 +08:00
|
|
|
event WithdrawRequestCreated(uint256 indexed requestId, address indexed user, uint256 ytAmount, uint256 usdcAmount, uint256 queueIndex);
|
|
|
|
|
event WithdrawRequestProcessed(uint256 indexed requestId, address indexed user, uint256 usdcAmount);
|
|
|
|
|
event BatchProcessed(uint256 startIndex, uint256 endIndex, uint256 processedCount, uint256 totalUsdcDistributed);
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
modifier onlyFactory() {
|
|
|
|
|
if (msg.sender != factory) revert Forbidden();
|
|
|
|
|
_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
modifier onlyManager() {
|
|
|
|
|
if (msg.sender != manager) revert Forbidden();
|
|
|
|
|
_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initialize(
|
|
|
|
|
string memory _name,
|
|
|
|
|
string memory _symbol,
|
|
|
|
|
address _manager,
|
|
|
|
|
uint256 _hardCap,
|
2025-12-24 16:41:26 +08:00
|
|
|
address _usdc,
|
2025-12-18 13:07:35 +08:00
|
|
|
uint256 _redemptionTime,
|
2025-12-24 16:41:26 +08:00
|
|
|
uint256 _initialYtPrice,
|
|
|
|
|
address _usdcPriceFeed
|
2025-12-18 13:07:35 +08:00
|
|
|
) external initializer {
|
|
|
|
|
__ERC20_init(_name, _symbol);
|
|
|
|
|
__UUPSUpgradeable_init();
|
|
|
|
|
__ReentrancyGuard_init();
|
|
|
|
|
__Pausable_init();
|
2025-12-24 16:41:26 +08:00
|
|
|
|
|
|
|
|
if (_usdcPriceFeed == address(0)) revert InvalidPriceFeed();
|
|
|
|
|
usdcPriceFeed = AggregatorV3Interface(_usdcPriceFeed);
|
|
|
|
|
usdcAddress = _usdc;
|
|
|
|
|
|
|
|
|
|
usdcDecimals = IERC20Metadata(usdcAddress).decimals();
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
factory = msg.sender;
|
|
|
|
|
manager = _manager;
|
|
|
|
|
hardCap = _hardCap;
|
|
|
|
|
|
|
|
|
|
ytPrice = _initialYtPrice == 0 ? PRICE_PRECISION : _initialYtPrice;
|
|
|
|
|
|
|
|
|
|
nextRedemptionTime = _redemptionTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _authorizeUpgrade(address newImplementation) internal override onlyFactory {}
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _getPriceConversionFactor() internal view returns (uint256) {
|
|
|
|
|
uint8 ytDecimals = decimals();
|
|
|
|
|
|
|
|
|
|
uint256 numerator = (10 ** ytDecimals) * PRICE_PRECISION;
|
|
|
|
|
|
|
|
|
|
uint256 denominator = (10 ** usdcDecimals) * CHAINLINK_PRICE_PRECISION;
|
|
|
|
|
|
|
|
|
|
return numerator / denominator;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-18 13:07:35 +08:00
|
|
|
function setHardCap(uint256 _hardCap) external onlyFactory {
|
|
|
|
|
if (_hardCap < totalSupply()) revert InvalidHardCap();
|
|
|
|
|
hardCap = _hardCap;
|
|
|
|
|
emit HardCapSet(_hardCap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setManager(address _manager) external onlyFactory {
|
|
|
|
|
manager = _manager;
|
|
|
|
|
emit ManagerSet(_manager);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pause() external onlyFactory {
|
|
|
|
|
_pause();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function unpause() external onlyFactory {
|
|
|
|
|
_unpause();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setNextRedemptionTime(uint256 _nextRedemptionTime) external onlyFactory {
|
|
|
|
|
nextRedemptionTime = _nextRedemptionTime;
|
|
|
|
|
emit NextRedemptionTimeSet(_nextRedemptionTime);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
function updatePrices(uint256 _ytPrice) external onlyFactory {
|
|
|
|
|
if (_ytPrice == 0) revert InvalidPrice();
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
ytPrice = _ytPrice;
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
emit PriceUpdated(_ytPrice, block.timestamp);
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
function depositYT(uint256 _usdcAmount)
|
|
|
|
|
external
|
2025-12-18 13:07:35 +08:00
|
|
|
nonReentrant
|
|
|
|
|
whenNotPaused
|
|
|
|
|
returns (uint256 ytAmount)
|
|
|
|
|
{
|
2025-12-24 16:41:26 +08:00
|
|
|
if (_usdcAmount == 0) revert InvalidAmount();
|
|
|
|
|
|
|
|
|
|
uint256 usdcPrice = _getUSDCPrice();
|
|
|
|
|
uint256 conversionFactor = _getPriceConversionFactor();
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
ytAmount = (_usdcAmount * usdcPrice * conversionFactor) / ytPrice;
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
if (hardCap > 0 && totalSupply() + ytAmount > hardCap) {
|
|
|
|
|
revert HardCapExceeded();
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
IERC20(usdcAddress).transferFrom(msg.sender, address(this), _usdcAmount);
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
_mint(msg.sender, ytAmount);
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
emit Buy(msg.sender, _usdcAmount, ytAmount);
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function withdrawYT(uint256 _ytAmount)
|
|
|
|
|
external
|
|
|
|
|
nonReentrant
|
|
|
|
|
whenNotPaused
|
2025-12-19 13:26:49 +08:00
|
|
|
returns (uint256 requestId)
|
2025-12-18 13:07:35 +08:00
|
|
|
{
|
|
|
|
|
if (_ytAmount == 0) revert InvalidAmount();
|
|
|
|
|
if (balanceOf(msg.sender) < _ytAmount) revert InsufficientYTA();
|
|
|
|
|
|
|
|
|
|
if (block.timestamp < nextRedemptionTime) {
|
|
|
|
|
revert StillInLockPeriod();
|
|
|
|
|
}
|
2025-12-24 16:41:26 +08:00
|
|
|
|
|
|
|
|
uint256 usdcPrice = _getUSDCPrice();
|
|
|
|
|
uint256 conversionFactor = _getPriceConversionFactor();
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
uint256 usdcAmount = (_ytAmount * ytPrice) / (usdcPrice * conversionFactor);
|
2025-12-19 13:26:49 +08:00
|
|
|
|
|
|
|
|
_burn(msg.sender, _ytAmount);
|
|
|
|
|
|
|
|
|
|
requestId = requestIdCounter;
|
|
|
|
|
withdrawRequests[requestId] = WithdrawRequest({
|
|
|
|
|
user: msg.sender,
|
|
|
|
|
ytAmount: _ytAmount,
|
2025-12-24 16:41:26 +08:00
|
|
|
usdcAmount: usdcAmount,
|
2025-12-19 13:26:49 +08:00
|
|
|
requestTime: block.timestamp,
|
|
|
|
|
queueIndex: requestId,
|
|
|
|
|
processed: false
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
userRequestIds[msg.sender].push(requestId);
|
|
|
|
|
|
|
|
|
|
requestIdCounter++;
|
|
|
|
|
|
|
|
|
|
pendingRequestsCount++;
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
emit WithdrawRequestCreated(requestId, msg.sender, _ytAmount, usdcAmount, requestId);
|
2025-12-19 13:26:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processBatchWithdrawals(uint256 _batchSize)
|
|
|
|
|
external
|
|
|
|
|
nonReentrant
|
|
|
|
|
whenNotPaused
|
|
|
|
|
returns (uint256 processedCount, uint256 totalDistributed)
|
|
|
|
|
{
|
|
|
|
|
if (msg.sender != manager && msg.sender != factory) {
|
|
|
|
|
revert Forbidden();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_batchSize == 0) revert InvalidBatchSize();
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
uint256 availableUSDC = IERC20(usdcAddress).balanceOf(address(this));
|
2025-12-19 13:26:49 +08:00
|
|
|
uint256 startIndex = processedUpToIndex;
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-19 13:26:49 +08:00
|
|
|
for (uint256 i = processedUpToIndex; i < requestIdCounter && processedCount < _batchSize; i++) {
|
|
|
|
|
WithdrawRequest storage request = withdrawRequests[i];
|
|
|
|
|
|
|
|
|
|
if (request.processed) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
if (availableUSDC >= request.usdcAmount) {
|
|
|
|
|
IERC20(usdcAddress).safeTransfer(request.user, request.usdcAmount);
|
2025-12-19 13:26:49 +08:00
|
|
|
|
|
|
|
|
request.processed = true;
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
availableUSDC -= request.usdcAmount;
|
|
|
|
|
totalDistributed += request.usdcAmount;
|
2025-12-19 13:26:49 +08:00
|
|
|
processedCount++;
|
|
|
|
|
|
|
|
|
|
pendingRequestsCount--;
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
emit WithdrawRequestProcessed(i, request.user, request.usdcAmount);
|
2025-12-19 13:26:49 +08:00
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-19 13:26:49 +08:00
|
|
|
if (processedCount > 0) {
|
|
|
|
|
for (uint256 i = processedUpToIndex; i < requestIdCounter; i++) {
|
|
|
|
|
if (!withdrawRequests[i].processed) {
|
|
|
|
|
processedUpToIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (i == requestIdCounter - 1) {
|
|
|
|
|
processedUpToIndex = requestIdCounter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-18 13:07:35 +08:00
|
|
|
|
2025-12-19 13:26:49 +08:00
|
|
|
emit BatchProcessed(startIndex, processedUpToIndex, processedCount, totalDistributed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getUserRequestIds(address _user) external view returns (uint256[] memory) {
|
|
|
|
|
return userRequestIds[_user];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getRequestDetails(uint256 _requestId) external view returns (WithdrawRequest memory request) {
|
|
|
|
|
if (_requestId >= requestIdCounter) revert RequestNotFound();
|
|
|
|
|
return withdrawRequests[_requestId];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getPendingRequestsCount() external view returns (uint256) {
|
|
|
|
|
return pendingRequestsCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getUserPendingRequests(address _user) external view returns (WithdrawRequest[] memory pendingRequests) {
|
|
|
|
|
uint256[] memory requestIds = userRequestIds[_user];
|
|
|
|
|
|
|
|
|
|
uint256 pendingCount = 0;
|
|
|
|
|
for (uint256 i = 0; i < requestIds.length; i++) {
|
|
|
|
|
if (!withdrawRequests[requestIds[i]].processed) {
|
|
|
|
|
pendingCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pendingRequests = new WithdrawRequest[](pendingCount);
|
|
|
|
|
uint256 index = 0;
|
|
|
|
|
for (uint256 i = 0; i < requestIds.length; i++) {
|
|
|
|
|
uint256 requestId = requestIds[i];
|
|
|
|
|
if (!withdrawRequests[requestId].processed) {
|
|
|
|
|
pendingRequests[index] = withdrawRequests[requestId];
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getQueueProgress() external view returns (
|
|
|
|
|
uint256 currentIndex,
|
|
|
|
|
uint256 totalRequests,
|
|
|
|
|
uint256 pendingRequests
|
|
|
|
|
) {
|
|
|
|
|
currentIndex = processedUpToIndex;
|
|
|
|
|
totalRequests = requestIdCounter;
|
|
|
|
|
pendingRequests = pendingRequestsCount;
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getTimeUntilNextRedemption() external view returns (uint256 remainingTime) {
|
|
|
|
|
if (block.timestamp >= nextRedemptionTime) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return nextRedemptionTime - block.timestamp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function canRedeemNow() external view returns (bool) {
|
|
|
|
|
return block.timestamp >= nextRedemptionTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function withdrawForManagement(address _to, uint256 _amount) external onlyManager nonReentrant whenNotPaused {
|
|
|
|
|
if (_amount == 0) revert InvalidAmount();
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
uint256 availableAssets = IERC20(usdcAddress).balanceOf(address(this));
|
2025-12-18 13:07:35 +08:00
|
|
|
if (_amount > availableAssets) revert InvalidAmount();
|
|
|
|
|
|
|
|
|
|
managedAssets += _amount;
|
2025-12-24 16:41:26 +08:00
|
|
|
IERC20(usdcAddress).safeTransfer(_to, _amount);
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
emit AssetsWithdrawn(_to, _amount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function depositManagedAssets(uint256 _amount) external onlyManager nonReentrant whenNotPaused {
|
|
|
|
|
if (_amount == 0) revert InvalidAmount();
|
|
|
|
|
|
|
|
|
|
if (_amount >= managedAssets) {
|
|
|
|
|
managedAssets = 0;
|
|
|
|
|
} else {
|
|
|
|
|
managedAssets -= _amount;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-26 13:23:50 +08:00
|
|
|
IERC20(usdcAddress).transferFrom(msg.sender, address(this), _amount);
|
2025-12-18 13:07:35 +08:00
|
|
|
|
|
|
|
|
emit AssetsDeposited(_amount);
|
|
|
|
|
}
|
2025-12-25 13:29:35 +08:00
|
|
|
|
2025-12-18 13:07:35 +08:00
|
|
|
function totalAssets() public view returns (uint256) {
|
2025-12-24 16:41:26 +08:00
|
|
|
return IERC20(usdcAddress).balanceOf(address(this)) + managedAssets;
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function idleAssets() public view returns (uint256) {
|
2025-12-24 16:41:26 +08:00
|
|
|
return IERC20(usdcAddress).balanceOf(address(this));
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
function previewBuy(uint256 _usdcAmount) external view returns (uint256 ytAmount) {
|
|
|
|
|
uint256 usdcPrice = _getUSDCPrice();
|
|
|
|
|
uint256 conversionFactor = _getPriceConversionFactor();
|
|
|
|
|
ytAmount = (_usdcAmount * usdcPrice * conversionFactor) / ytPrice;
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 16:41:26 +08:00
|
|
|
function previewSell(uint256 _ytAmount) external view returns (uint256 usdcAmount) {
|
|
|
|
|
uint256 usdcPrice = _getUSDCPrice();
|
|
|
|
|
uint256 conversionFactor = _getPriceConversionFactor();
|
|
|
|
|
usdcAmount = (_ytAmount * ytPrice) / (usdcPrice * conversionFactor);
|
2025-12-18 13:07:35 +08:00
|
|
|
}
|
2025-12-25 13:29:35 +08:00
|
|
|
|
2025-12-18 13:07:35 +08:00
|
|
|
function getVaultInfo() external view returns (
|
|
|
|
|
uint256 _totalAssets,
|
|
|
|
|
uint256 _idleAssets,
|
|
|
|
|
uint256 _managedAssets,
|
|
|
|
|
uint256 _totalSupply,
|
|
|
|
|
uint256 _hardCap,
|
2025-12-24 16:41:26 +08:00
|
|
|
uint256 _usdcPrice,
|
2025-12-18 13:07:35 +08:00
|
|
|
uint256 _ytPrice,
|
|
|
|
|
uint256 _nextRedemptionTime
|
|
|
|
|
) {
|
2025-12-24 16:41:26 +08:00
|
|
|
_usdcPrice = _getUSDCPrice();
|
2025-12-18 13:07:35 +08:00
|
|
|
_totalAssets = totalAssets();
|
|
|
|
|
_idleAssets = idleAssets();
|
|
|
|
|
_managedAssets = managedAssets;
|
|
|
|
|
_totalSupply = totalSupply();
|
|
|
|
|
_hardCap = hardCap;
|
|
|
|
|
_ytPrice = ytPrice;
|
|
|
|
|
_nextRedemptionTime = nextRedemptionTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint256[50] private __gap;
|
2025-12-25 13:29:35 +08:00
|
|
|
}
|