Files
assetxContracts/contracts/ytVault/YTAssetFactory.sol

440 lines
14 KiB
Solidity
Raw Normal View History

2025-12-18 13:07:35 +08:00
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "./YTAssetVault.sol";
/**
* @title YTAssetFactory
* @notice YT资产金库合约的工厂
* @dev UUPS可升级合约
*/
contract YTAssetFactory is Initializable, UUPSUpgradeable, OwnableUpgradeable {
error InvalidAddress();
error VaultNotExists();
error InvalidHardCap();
2025-12-23 14:05:41 +08:00
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
2025-12-18 13:07:35 +08:00
/// @notice YTAssetVault实现合约地址
address public vaultImplementation;
/// @notice 所有创建的vault地址列表
address[] public allVaults;
/// @notice vault地址 => 是否存在
mapping(address => bool) public isVault;
/// @notice 默认硬顶值0表示无限制
uint256 public defaultHardCap;
event VaultCreated(
address indexed vault,
address indexed manager,
string name,
string symbol,
uint256 hardCap,
uint256 index
);
event VaultImplementationUpdated(address indexed newImplementation);
event DefaultHardCapSet(uint256 newDefaultHardCap);
event HardCapSet(address indexed vault, uint256 newHardCap);
2025-12-24 16:41:26 +08:00
event PricesUpdated(address indexed vault, uint256 ytPrice);
2025-12-18 13:07:35 +08:00
event NextRedemptionTimeSet(address indexed vault, uint256 redemptionTime);
/**
* @notice
* @param _vaultImplementation YTAssetVault实现合约地址
* @param _defaultHardCap
*/
function initialize(
address _vaultImplementation,
uint256 _defaultHardCap
) external initializer {
if (_vaultImplementation == address(0)) revert InvalidAddress();
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();
vaultImplementation = _vaultImplementation;
defaultHardCap = _defaultHardCap;
}
/**
* @notice owner可调用
* @param newImplementation
*/
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
/**
* @notice YTAssetVault实现合约
* @param _newImplementation
*/
function setVaultImplementation(address _newImplementation) external onlyOwner {
if (_newImplementation == address(0)) revert InvalidAddress();
vaultImplementation = _newImplementation;
emit VaultImplementationUpdated(_newImplementation);
}
/**
* @notice
* @param _defaultHardCap
*/
function setDefaultHardCap(uint256 _defaultHardCap) external onlyOwner {
defaultHardCap = _defaultHardCap;
emit DefaultHardCapSet(_defaultHardCap);
}
/**
* @notice YTAssetVault
* @param _name YT代币名称
* @param _symbol YT代币符号
* @param _manager
* @param _hardCap 0使
2025-12-24 16:41:26 +08:00
* @param _usdc USDC代币地址0使
2025-12-18 13:07:35 +08:00
* @param _redemptionTime Unix时间戳
* @param _initialYtPrice YT价格1e300使1.0
2025-12-24 16:41:26 +08:00
* @param _usdcPriceFeed Chainlink USDC价格Feed地址
2025-12-18 13:07:35 +08:00
* @return vault vault地址
*/
function createVault(
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 onlyOwner returns (address vault) {
if (_manager == address(0)) revert InvalidAddress();
// 如果传入0使用默认硬顶
uint256 actualHardCap = _hardCap == 0 ? defaultHardCap : _hardCap;
// 编码初始化数据
bytes memory initData = abi.encodeWithSelector(
YTAssetVault.initialize.selector,
_name,
_symbol,
_manager,
actualHardCap,
2025-12-24 16:41:26 +08:00
_usdc,
2025-12-18 13:07:35 +08:00
_redemptionTime,
2025-12-24 16:41:26 +08:00
_initialYtPrice,
_usdcPriceFeed
2025-12-18 13:07:35 +08:00
);
// 部署代理合约
vault = address(new ERC1967Proxy(vaultImplementation, initData));
// 记录vault信息
allVaults.push(vault);
isVault[vault] = true;
emit VaultCreated(
vault,
_manager,
_name,
_symbol,
actualHardCap,
allVaults.length - 1
);
}
/**
* @notice vault
* @param _names YT代币名称数组
* @param _symbols YT代币符号数组
* @param _managers
* @param _hardCaps
2025-12-24 16:41:26 +08:00
* @param _usdc USDC代币地址0使
2025-12-18 13:07:35 +08:00
* @param _redemptionTimes Unix时间戳
* @param _initialYtPrices YT价格数组1e30
2025-12-24 16:41:26 +08:00
* @param _usdcPriceFeed Chainlink USDC价格Feed地址
2025-12-18 13:07:35 +08:00
* @return vaults vault地址数组
*/
function createVaultBatch(
string[] memory _names,
string[] memory _symbols,
address[] memory _managers,
uint256[] memory _hardCaps,
2025-12-24 16:41:26 +08:00
address _usdc,
2025-12-18 13:07:35 +08:00
uint256[] memory _redemptionTimes,
2025-12-24 16:41:26 +08:00
uint256[] memory _initialYtPrices,
address _usdcPriceFeed
2025-12-29 11:08:34 +08:00
) external onlyOwner returns (address[] memory vaults) {
2025-12-18 13:07:35 +08:00
require(
_names.length == _symbols.length &&
_names.length == _managers.length &&
_names.length == _hardCaps.length &&
_names.length == _redemptionTimes.length &&
_names.length == _initialYtPrices.length,
"Length mismatch"
);
vaults = new address[](_names.length);
for (uint256 i = 0; i < _names.length; i++) {
vaults[i] = this.createVault(
_names[i],
_symbols[i],
_managers[i],
_hardCaps[i],
2025-12-24 16:41:26 +08:00
_usdc,
2025-12-18 13:07:35 +08:00
_redemptionTimes[i],
2025-12-24 16:41:26 +08:00
_initialYtPrices[i],
_usdcPriceFeed
2025-12-18 13:07:35 +08:00
);
}
}
/**
* @notice vault的硬顶
* @param _vault vault地址
* @param _hardCap
*/
function setHardCap(address _vault, uint256 _hardCap) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
YTAssetVault(_vault).setHardCap(_hardCap);
emit HardCapSet(_vault, _hardCap);
}
/**
* @notice
* @param _vaults vault地址数组
* @param _hardCaps
*/
function setHardCapBatch(
address[] memory _vaults,
uint256[] memory _hardCaps
) external onlyOwner {
require(_vaults.length == _hardCaps.length, "Length mismatch");
for (uint256 i = 0; i < _vaults.length; i++) {
if (!isVault[_vaults[i]]) revert VaultNotExists();
YTAssetVault(_vaults[i]).setHardCap(_hardCaps[i]);
emit HardCapSet(_vaults[i], _hardCaps[i]);
}
}
/**
* @notice vault的管理员
* @param _vault vault地址
* @param _manager
*/
function setVaultManager(address _vault, address _manager) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
if (_manager == address(0)) revert InvalidAddress();
YTAssetVault(_vault).setManager(_manager);
}
/**
* @notice vault的下一个赎回时间
* @param _vault vault地址
* @param _nextRedemptionTime Unix时间戳
*/
function setVaultNextRedemptionTime(address _vault, uint256 _nextRedemptionTime) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
YTAssetVault(_vault).setNextRedemptionTime(_nextRedemptionTime);
emit NextRedemptionTimeSet(_vault, _nextRedemptionTime);
}
/**
* @notice
* @param _vaults vault地址数组
* @param _nextRedemptionTime
*/
function setVaultNextRedemptionTimeBatch(
address[] memory _vaults,
uint256 _nextRedemptionTime
) external onlyOwner {
for (uint256 i = 0; i < _vaults.length; i++) {
if (!isVault[_vaults[i]]) revert VaultNotExists();
YTAssetVault(_vaults[i]).setNextRedemptionTime(_nextRedemptionTime);
emit NextRedemptionTimeSet(_vaults[i], _nextRedemptionTime);
}
}
/**
* @notice vault
* @param _vault vault地址
*/
function pauseVault(address _vault) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
YTAssetVault(_vault).pause();
}
/**
* @notice vault
* @param _vault vault地址
*/
function unpauseVault(address _vault) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
YTAssetVault(_vault).unpause();
}
/**
* @notice vaults
* @param _vaults vault地址数组
*/
function pauseVaultBatch(address[] memory _vaults) external onlyOwner {
for (uint256 i = 0; i < _vaults.length; i++) {
if (!isVault[_vaults[i]]) revert VaultNotExists();
YTAssetVault(_vaults[i]).pause();
}
}
/**
* @notice vaults
* @param _vaults vault地址数组
*/
function unpauseVaultBatch(address[] memory _vaults) external onlyOwner {
for (uint256 i = 0; i < _vaults.length; i++) {
if (!isVault[_vaults[i]]) revert VaultNotExists();
YTAssetVault(_vaults[i]).unpause();
}
}
/**
* @notice vault价格
* @param _vault vault地址
* @param _ytPrice YT价格1e30
*/
function updateVaultPrices(
2025-12-24 16:41:26 +08:00
address _vault,
2025-12-18 13:07:35 +08:00
uint256 _ytPrice
) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
2025-12-24 16:41:26 +08:00
YTAssetVault(_vault).updatePrices(_ytPrice);
emit PricesUpdated(_vault, _ytPrice);
2025-12-18 13:07:35 +08:00
}
/**
* @notice
* @param _vaults vault地址数组
* @param _ytPrices YT价格数组1e30
*/
function updateVaultPricesBatch(
address[] memory _vaults,
uint256[] memory _ytPrices
) external onlyOwner {
2025-12-24 16:41:26 +08:00
require(_vaults.length == _ytPrices.length, "Length mismatch");
2025-12-18 13:07:35 +08:00
for (uint256 i = 0; i < _vaults.length; i++) {
if (!isVault[_vaults[i]]) revert VaultNotExists();
2025-12-24 16:41:26 +08:00
YTAssetVault(_vaults[i]).updatePrices(_ytPrices[i]);
emit PricesUpdated(_vaults[i], _ytPrices[i]);
2025-12-18 13:07:35 +08:00
}
}
/**
* @notice vault
* @param _vault vault地址
* @param _newImplementation
*/
function upgradeVault(address _vault, address _newImplementation) external onlyOwner {
if (!isVault[_vault]) revert VaultNotExists();
if (_newImplementation == address(0)) revert InvalidAddress();
YTAssetVault(_vault).upgradeToAndCall(_newImplementation, "");
}
/**
* @notice vault
* @param _vaults vault地址数组
* @param _newImplementation
*/
function upgradeVaultBatch(
address[] memory _vaults,
address _newImplementation
) external onlyOwner {
if (_newImplementation == address(0)) revert InvalidAddress();
for (uint256 i = 0; i < _vaults.length; i++) {
if (!isVault[_vaults[i]]) revert VaultNotExists();
YTAssetVault(_vaults[i]).upgradeToAndCall(_newImplementation, "");
}
}
/**
* @notice vault数量
*/
function getVaultCount() external view returns (uint256) {
return allVaults.length;
}
/**
* @notice vault地址
* @param _start
* @param _end
*/
function getVaults(uint256 _start, uint256 _end)
external
view
returns (address[] memory vaults)
{
require(_start < _end && _end <= allVaults.length, "Invalid range");
vaults = new address[](_end - _start);
for (uint256 i = _start; i < _end; i++) {
vaults[i - _start] = allVaults[i];
}
}
/**
* @notice vault地址
*/
function getAllVaults() external view returns (address[] memory) {
return allVaults;
}
/**
* @notice vault详细信息
* @param _vault vault地址
*/
function getVaultInfo(address _vault) external view returns (
bool exists,
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
) {
exists = isVault[_vault];
if (!exists) return (false, 0, 0, 0, 0, 0, 0, 0, 0);
(
totalAssets,
idleAssets,
managedAssets,
totalSupply,
hardCap,
2025-12-24 16:41:26 +08:00
usdcPrice,
2025-12-18 13:07:35 +08:00
ytPrice,
nextRedemptionTime
) = YTAssetVault(_vault).getVaultInfo();
}
/**
* @dev
* 50slot = 50 * 32 bytes = 1600 bytes
*/
uint256[50] private __gap;
}