// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "../contracts/vault/YTAssetVault.sol"; import "../contracts/vault/YTAssetFactory.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; // Mock WUSD token for testing contract MockWUSD is ERC20 { constructor() ERC20("Wrapped USD", "WUSD") { _mint(msg.sender, 10000000 * 1e18); // 铸造1000万WUSD用于测试 } function mint(address to, uint256 amount) external { _mint(to, amount); } } contract VaultTest is Test { YTAssetFactory public factory; YTAssetVault public vaultImplementation; YTAssetVault public vault; MockWUSD public wusd; address public owner; address public manager; address public user1; address public user2; // 常量 uint256 constant PRICE_PRECISION = 1e30; uint256 constant INITIAL_WUSD_PRICE = 1e30; // 1.0 uint256 constant INITIAL_YT_PRICE = 1e30; // 1.0 uint256 constant HARD_CAP = 1000000 * 1e18; // 100万YT event VaultCreated( address indexed vault, address indexed manager, string name, string symbol, uint256 hardCap, uint256 index ); event Buy(address indexed user, uint256 wusdAmount, uint256 ytAmount); event Sell(address indexed user, uint256 ytAmount, uint256 wusdAmount); event PriceUpdated(uint256 wusdPrice, uint256 ytPrice, uint256 timestamp); event AssetsWithdrawn(address indexed to, uint256 amount); event AssetsDeposited(uint256 amount); event HardCapSet(uint256 newHardCap); event NextRedemptionTimeSet(uint256 newRedemptionTime); function setUp() public { // 设置测试账户 owner = address(this); manager = makeAddr("manager"); user1 = makeAddr("user1"); user2 = makeAddr("user2"); // 部署Mock WUSD wusd = new MockWUSD(); // 部署实现合约 vaultImplementation = new YTAssetVault(); // 部署并初始化Factory YTAssetFactory factoryImpl = new YTAssetFactory(); bytes memory factoryInitData = abi.encodeWithSelector( YTAssetFactory.initialize.selector, address(vaultImplementation), HARD_CAP // 默认硬顶 ); ERC1967Proxy factoryProxy = new ERC1967Proxy(address(factoryImpl), factoryInitData); factory = YTAssetFactory(address(factoryProxy)); // 给测试用户分配WUSD wusd.transfer(user1, 100000 * 1e18); // 10万WUSD wusd.transfer(user2, 100000 * 1e18); // 10万WUSD wusd.transfer(manager, 100000 * 1e18); // 10万WUSD给manager } function _createVault() internal returns (YTAssetVault) { uint256 redemptionTime = block.timestamp + 30 days; address vaultAddr = factory.createVault( "YT-A Token", "YT-A", manager, HARD_CAP, address(wusd), redemptionTime, INITIAL_WUSD_PRICE, INITIAL_YT_PRICE ); return YTAssetVault(vaultAddr); } function test_01_FactoryInitialization() public { assertEq(factory.vaultImplementation(), address(vaultImplementation)); assertEq(factory.defaultHardCap(), HARD_CAP); assertEq(factory.owner(), owner); } function test_02_CreateVault() public { uint256 redemptionTime = block.timestamp + 30 days; vm.expectEmit(false, true, false, true); emit VaultCreated( address(0), // vault地址未知,所以用0 manager, "YT-A Token", "YT-A", HARD_CAP, 0 // 第一个vault,索引为0 ); address vaultAddr = factory.createVault( "YT-A Token", "YT-A", manager, HARD_CAP, address(wusd), redemptionTime, INITIAL_WUSD_PRICE, INITIAL_YT_PRICE ); vault = YTAssetVault(vaultAddr); // 验证vault基本信息 assertEq(vault.name(), "YT-A Token"); assertEq(vault.symbol(), "YT-A"); assertEq(vault.manager(), manager); assertEq(vault.hardCap(), HARD_CAP); assertEq(vault.wusdAddress(), address(wusd)); assertEq(vault.wusdPrice(), INITIAL_WUSD_PRICE); assertEq(vault.ytPrice(), INITIAL_YT_PRICE); assertEq(vault.nextRedemptionTime(), redemptionTime); assertEq(vault.factory(), address(factory)); // 验证factory记录 assertEq(factory.getVaultCount(), 1); assertTrue(factory.isVault(vaultAddr)); } function test_03_CreateVaultWithCustomPrices() public { uint256 customWusdPrice = 1050000000000000000000000000000; // 1.05 uint256 customYtPrice = 1020000000000000000000000000000; // 1.02 uint256 redemptionTime = block.timestamp + 60 days; address vaultAddr = factory.createVault( "YT-B Token", "YT-B", manager, HARD_CAP, address(wusd), redemptionTime, customWusdPrice, customYtPrice ); YTAssetVault customVault = YTAssetVault(vaultAddr); assertEq(customVault.wusdPrice(), customWusdPrice); assertEq(customVault.ytPrice(), customYtPrice); } function test_04_CreateVaultWithZeroPrices() public { // 传入0价格应该使用默认值 uint256 redemptionTime = block.timestamp + 30 days; address vaultAddr = factory.createVault( "YT-C Token", "YT-C", manager, HARD_CAP, address(wusd), redemptionTime, 0, // 使用默认价格 0 // 使用默认价格 ); YTAssetVault defaultVault = YTAssetVault(vaultAddr); assertEq(defaultVault.wusdPrice(), PRICE_PRECISION); // 1.0 assertEq(defaultVault.ytPrice(), PRICE_PRECISION); // 1.0 } function test_05_CannotCreateVaultWithZeroManager() public { vm.expectRevert(YTAssetFactory.InvalidAddress.selector); factory.createVault( "YT-D Token", "YT-D", address(0), // 无效的manager地址 HARD_CAP, address(wusd), block.timestamp + 30 days, INITIAL_WUSD_PRICE, INITIAL_YT_PRICE ); } function test_06_CreateVaultOnlyOwner() public { vm.prank(user1); vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", user1)); factory.createVault( "YT-E Token", "YT-E", manager, HARD_CAP, address(wusd), block.timestamp + 30 days, INITIAL_WUSD_PRICE, INITIAL_YT_PRICE ); } function test_07_DepositYT() public { vault = _createVault(); uint256 depositAmount = 1000 * 1e18; // 1000 WUSD uint256 expectedYtAmount = 1000 * 1e18; // 价格1:1,获得1000 YT // 授权 vm.startPrank(user1); wusd.approve(address(vault), depositAmount); // 预览购买 uint256 previewAmount = vault.previewBuy(depositAmount); assertEq(previewAmount, expectedYtAmount); // 存款 vm.expectEmit(true, false, false, true); emit Buy(user1, depositAmount, expectedYtAmount); uint256 ytReceived = vault.depositYT(depositAmount); vm.stopPrank(); // 验证结果 assertEq(ytReceived, expectedYtAmount); assertEq(vault.balanceOf(user1), expectedYtAmount); assertEq(vault.totalSupply(), expectedYtAmount); assertEq(wusd.balanceOf(address(vault)), depositAmount); assertEq(vault.totalAssets(), depositAmount); assertEq(vault.idleAssets(), depositAmount); } function test_08_DepositYTWithDifferentPrices() public { vault = _createVault(); // 更新价格: WUSD = 1.05, YT = 1.02 factory.updateVaultPrices( address(vault), 1050000000000000000000000000000, // 1.05 1020000000000000000000000000000 // 1.02 ); uint256 depositAmount = 1000 * 1e18; // 1000 WUSD // ytAmount = 1000 * 1.05 / 1.02 = 1029.411764705882352941 YT uint256 expectedYtAmount = (depositAmount * 1050000000000000000000000000000) / 1020000000000000000000000000000; vm.startPrank(user1); wusd.approve(address(vault), depositAmount); uint256 ytReceived = vault.depositYT(depositAmount); vm.stopPrank(); // 精确验证计算结果 assertEq(ytReceived, expectedYtAmount); assertEq(ytReceived, 1029411764705882352941); // 约1029.41 YT } function test_09_DepositYTMultipleUsers() public { vault = _createVault(); uint256 amount1 = 1000 * 1e18; uint256 amount2 = 2000 * 1e18; // User1存款 vm.startPrank(user1); wusd.approve(address(vault), amount1); vault.depositYT(amount1); vm.stopPrank(); // User2存款 vm.startPrank(user2); wusd.approve(address(vault), amount2); vault.depositYT(amount2); vm.stopPrank(); // 验证余额 assertEq(vault.balanceOf(user1), amount1); assertEq(vault.balanceOf(user2), amount2); assertEq(vault.totalSupply(), amount1 + amount2); assertEq(vault.totalAssets(), amount1 + amount2); } function test_10_CannotDepositZeroAmount() public { vault = _createVault(); vm.startPrank(user1); vm.expectRevert(YTAssetVault.InvalidAmount.selector); vault.depositYT(0); vm.stopPrank(); } function test_11_DepositYTHardCapEnforcement() public { vault = _createVault(); // 尝试存款超过硬顶 uint256 overCapAmount = HARD_CAP + 1000 * 1e18; vm.startPrank(user1); wusd.mint(user1, overCapAmount); // 铸造足够的WUSD wusd.approve(address(vault), overCapAmount); vm.expectRevert(YTAssetVault.HardCapExceeded.selector); vault.depositYT(overCapAmount); vm.stopPrank(); } function test_12_DepositYTExactlyAtHardCap() public { vault = _createVault(); vm.startPrank(user1); wusd.mint(user1, HARD_CAP); wusd.approve(address(vault), HARD_CAP); vault.depositYT(HARD_CAP); vm.stopPrank(); assertEq(vault.totalSupply(), HARD_CAP); assertEq(vault.balanceOf(user1), HARD_CAP); } function test_13_WithdrawYT() public { vault = _createVault(); // 先存款 uint256 depositAmount = 1000 * 1e18; vm.startPrank(user1); wusd.approve(address(vault), depositAmount); vault.depositYT(depositAmount); vm.stopPrank(); // 快进到赎回时间之后 vm.warp(vault.nextRedemptionTime() + 1); // 提款 uint256 withdrawAmount = 500 * 1e18; // 提取500 YT uint256 expectedWusd = 500 * 1e18; // 价格1:1,获得500 WUSD uint256 user1WusdBefore = wusd.balanceOf(user1); vm.startPrank(user1); vm.expectEmit(true, false, false, true); emit Sell(user1, withdrawAmount, expectedWusd); uint256 wusdReceived = vault.withdrawYT(withdrawAmount); vm.stopPrank(); // 验证结果 assertEq(wusdReceived, expectedWusd); assertEq(vault.balanceOf(user1), depositAmount - withdrawAmount); assertEq(vault.totalSupply(), depositAmount - withdrawAmount); assertEq(wusd.balanceOf(user1), user1WusdBefore + expectedWusd); } function test_14_WithdrawYTWithDifferentPrices() public { vault = _createVault(); // 存款 uint256 depositAmount = 1000 * 1e18; vm.startPrank(user1); wusd.approve(address(vault), depositAmount); vault.depositYT(depositAmount); vm.stopPrank(); // 更新价格: WUSD = 0.98, YT = 1.05 (YT升值) factory.updateVaultPrices( address(vault), 980000000000000000000000000000, // 0.98 1050000000000000000000000000000 // 1.05 ); // 快进到赎回时间 vm.warp(vault.nextRedemptionTime() + 1); // 提款500 YT uint256 withdrawAmount = 500 * 1e18; // wusdAmount = 500 * 1.05 / 0.98 = 535.714285714285714285 WUSD uint256 expectedWusd = (withdrawAmount * 1050000000000000000000000000000) / 980000000000000000000000000000; vm.startPrank(user1); uint256 wusdReceived = vault.withdrawYT(withdrawAmount); vm.stopPrank(); assertEq(wusdReceived, expectedWusd); assertEq(wusdReceived, 535714285714285714285); // 约535.71 WUSD } function test_15_CannotWithdrawBeforeRedemptionTime() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); // 尝试在赎回时间前提款 vm.expectRevert(YTAssetVault.StillInLockPeriod.selector); vault.withdrawYT(500 * 1e18); vm.stopPrank(); } function test_16_CannotWithdrawZeroAmount() public { vault = _createVault(); vm.warp(vault.nextRedemptionTime() + 1); vm.startPrank(user1); vm.expectRevert(YTAssetVault.InvalidAmount.selector); vault.withdrawYT(0); vm.stopPrank(); } function test_17_CannotWithdrawMoreThanBalance() public { vault = _createVault(); vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); vm.stopPrank(); vm.warp(vault.nextRedemptionTime() + 1); vm.startPrank(user1); vm.expectRevert(YTAssetVault.InsufficientYTA.selector); vault.withdrawYT(2000 * 1e18); vm.stopPrank(); } function test_18_CannotWithdrawWhenInsufficientWUSD() public { vault = _createVault(); // User1存款 vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); vm.stopPrank(); // Manager提取所有WUSD vm.prank(manager); vault.withdrawForManagement(manager, 1000 * 1e18); // 快进到赎回时间 vm.warp(vault.nextRedemptionTime() + 1); // User1尝试提款,但vault中没有WUSD vm.startPrank(user1); vm.expectRevert(YTAssetVault.InsufficientWUSD.selector); vault.withdrawYT(500 * 1e18); vm.stopPrank(); } function test_19_UpdatePrices() public { vault = _createVault(); uint256 newWusdPrice = 1050000000000000000000000000000; // 1.05 uint256 newYtPrice = 1020000000000000000000000000000; // 1.02 vm.expectEmit(false, false, false, true); emit PriceUpdated(newWusdPrice, newYtPrice, block.timestamp); factory.updateVaultPrices(address(vault), newWusdPrice, newYtPrice); assertEq(vault.wusdPrice(), newWusdPrice); assertEq(vault.ytPrice(), newYtPrice); } function test_20_UpdatePricesMultipleTimes() public { vault = _createVault(); // 第一次更新 factory.updateVaultPrices( address(vault), 1050000000000000000000000000000, 1020000000000000000000000000000 ); assertEq(vault.wusdPrice(), 1050000000000000000000000000000); assertEq(vault.ytPrice(), 1020000000000000000000000000000); // 第二次更新 factory.updateVaultPrices( address(vault), 1030000000000000000000000000000, 1010000000000000000000000000000 ); assertEq(vault.wusdPrice(), 1030000000000000000000000000000); assertEq(vault.ytPrice(), 1010000000000000000000000000000); } function test_21_UpdatePricesOnlyFactory() public { vault = _createVault(); // 测试非factory调用者(包括manager)无法直接调用 vm.prank(user1); vm.expectRevert(YTAssetVault.Forbidden.selector); vault.updatePrices(1050000000000000000000000000000, 1020000000000000000000000000000); // manager也不能直接调用 vm.prank(manager); vm.expectRevert(YTAssetVault.Forbidden.selector); vault.updatePrices(1050000000000000000000000000000, 1020000000000000000000000000000); } function test_22_UpdatePricesFactoryCanCall() public { vault = _createVault(); // Factory也可以调用updatePrices(通过factory) vm.prank(owner); factory.updateVaultPrices( address(vault), 1050000000000000000000000000000, 1020000000000000000000000000000 ); assertEq(vault.wusdPrice(), 1050000000000000000000000000000); assertEq(vault.ytPrice(), 1020000000000000000000000000000); } function test_23_CannotUpdatePricesWithZero() public { vault = _createVault(); vm.expectRevert(YTAssetVault.InvalidPrice.selector); factory.updateVaultPrices(address(vault), 0, 1020000000000000000000000000000); vm.expectRevert(YTAssetVault.InvalidPrice.selector); factory.updateVaultPrices(address(vault), 1050000000000000000000000000000, 0); } function test_24_WithdrawForManagement() public { vault = _createVault(); // 先存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); // Manager提取用于投资 uint256 withdrawAmount = 5000 * 1e18; uint256 managerBalanceBefore = wusd.balanceOf(manager); vm.expectEmit(true, false, false, true); emit AssetsWithdrawn(manager, withdrawAmount); vm.prank(manager); vault.withdrawForManagement(manager, withdrawAmount); // 验证 assertEq(vault.managedAssets(), withdrawAmount); assertEq(vault.idleAssets(), 5000 * 1e18); assertEq(vault.totalAssets(), 10000 * 1e18); // totalAssets = idle + managed assertEq(wusd.balanceOf(manager), managerBalanceBefore + withdrawAmount); } function test_25_DepositManagedAssetsFullReturn() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); // Manager提取 vm.prank(manager); vault.withdrawForManagement(manager, 5000 * 1e18); // Manager归还全部(无盈亏) vm.startPrank(manager); wusd.approve(address(vault), 5000 * 1e18); vm.expectEmit(false, false, false, true); emit AssetsDeposited(5000 * 1e18); vault.depositManagedAssets(5000 * 1e18); vm.stopPrank(); // 验证 assertEq(vault.managedAssets(), 0); assertEq(vault.idleAssets(), 10000 * 1e18); assertEq(vault.totalAssets(), 10000 * 1e18); } function test_26_DepositManagedAssetsWithProfit() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); // Manager提取 vm.prank(manager); vault.withdrawForManagement(manager, 5000 * 1e18); // Manager归还本金+利润 uint256 returnAmount = 6000 * 1e18; // 赚了1000 WUSD vm.startPrank(manager); wusd.approve(address(vault), returnAmount); vault.depositManagedAssets(returnAmount); vm.stopPrank(); // 验证 assertEq(vault.managedAssets(), 0); assertEq(vault.idleAssets(), 11000 * 1e18); // 5000 + 6000 assertEq(vault.totalAssets(), 11000 * 1e18); // 增加了1000的利润 } function test_27_DepositManagedAssetsPartialReturn() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); // Manager提取 vm.prank(manager); vault.withdrawForManagement(manager, 5000 * 1e18); // Manager部分归还 uint256 returnAmount = 3000 * 1e18; vm.startPrank(manager); wusd.approve(address(vault), returnAmount); vault.depositManagedAssets(returnAmount); vm.stopPrank(); // 验证 assertEq(vault.managedAssets(), 2000 * 1e18); // 还有2000在外面 assertEq(vault.idleAssets(), 8000 * 1e18); // 5000 + 3000 assertEq(vault.totalAssets(), 10000 * 1e18); // 总资产不变 } function test_28_WithdrawForManagementOnlyManager() public { vault = _createVault(); vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); vm.stopPrank(); vm.prank(user1); vm.expectRevert(YTAssetVault.Forbidden.selector); vault.withdrawForManagement(user1, 500 * 1e18); } function test_29_CannotWithdrawMoreThanAvailable() public { vault = _createVault(); vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); vm.stopPrank(); vm.prank(manager); vm.expectRevert(YTAssetVault.InvalidAmount.selector); vault.withdrawForManagement(manager, 2000 * 1e18); } function test_30_SetHardCap() public { vault = _createVault(); uint256 newHardCap = 2000000 * 1e18; vm.expectEmit(false, false, false, true); emit HardCapSet(newHardCap); factory.setHardCap(address(vault), newHardCap); assertEq(vault.hardCap(), newHardCap); } function test_31_CannotSetHardCapBelowTotalSupply() public { vault = _createVault(); // 先存款 vm.startPrank(user1); wusd.approve(address(vault), 100000 * 1e18); vault.depositYT(100000 * 1e18); vm.stopPrank(); // 尝试设置低于当前总供应量的硬顶 vm.expectRevert(YTAssetVault.InvalidHardCap.selector); factory.setHardCap(address(vault), 50000 * 1e18); } function test_32_SetNextRedemptionTime() public { vault = _createVault(); uint256 newRedemptionTime = block.timestamp + 90 days; vm.expectEmit(false, false, false, true); emit NextRedemptionTimeSet(newRedemptionTime); factory.setVaultNextRedemptionTime(address(vault), newRedemptionTime); assertEq(vault.nextRedemptionTime(), newRedemptionTime); } function test_33_BatchUpdatePrices() public { // 创建多个vault address vault1 = factory.createVault( "YT-A", "YT-A", manager, HARD_CAP, address(wusd), block.timestamp + 30 days, INITIAL_WUSD_PRICE, INITIAL_YT_PRICE ); address vault2 = factory.createVault( "YT-B", "YT-B", manager, HARD_CAP, address(wusd), block.timestamp + 30 days, INITIAL_WUSD_PRICE, INITIAL_YT_PRICE ); address[] memory vaults = new address[](2); vaults[0] = vault1; vaults[1] = vault2; uint256[] memory wusdPrices = new uint256[](2); wusdPrices[0] = 1050000000000000000000000000000; wusdPrices[1] = 1030000000000000000000000000000; uint256[] memory ytPrices = new uint256[](2); ytPrices[0] = 1020000000000000000000000000000; ytPrices[1] = 1010000000000000000000000000000; factory.updateVaultPricesBatch(vaults, wusdPrices, ytPrices); assertEq(YTAssetVault(vault1).wusdPrice(), wusdPrices[0]); assertEq(YTAssetVault(vault1).ytPrice(), ytPrices[0]); assertEq(YTAssetVault(vault2).wusdPrice(), wusdPrices[1]); assertEq(YTAssetVault(vault2).ytPrice(), ytPrices[1]); } function test_34_GetVaultInfo() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); // Manager提取部分资金 vm.prank(manager); vault.withdrawForManagement(manager, 3000 * 1e18); ( uint256 totalAssets, uint256 idleAssets, uint256 managedAssets, uint256 totalSupply, uint256 hardCap, uint256 wusdPrice, uint256 ytPrice, uint256 nextRedemptionTime ) = vault.getVaultInfo(); assertEq(totalAssets, 10000 * 1e18); assertEq(idleAssets, 7000 * 1e18); assertEq(managedAssets, 3000 * 1e18); assertEq(totalSupply, 10000 * 1e18); assertEq(hardCap, HARD_CAP); assertEq(wusdPrice, INITIAL_WUSD_PRICE); assertEq(ytPrice, INITIAL_YT_PRICE); assertEq(nextRedemptionTime, vault.nextRedemptionTime()); } function test_35_GetFactoryVaultInfo() public { vault = _createVault(); ( bool exists, uint256 totalAssets, ,, // idleAssets, managedAssets , // totalSupply uint256 hardCap, ,, // wusdPrice, ytPrice // nextRedemptionTime ) = factory.getVaultInfo(address(vault)); assertTrue(exists); assertEq(totalAssets, 0); assertEq(hardCap, HARD_CAP); } function test_36_PreviewFunctions() public { vault = _createVault(); // 更新价格 factory.updateVaultPrices( address(vault), 1050000000000000000000000000000, // WUSD = 1.05 1020000000000000000000000000000 // YT = 1.02 ); // 预览买入 uint256 wusdAmount = 1000 * 1e18; uint256 expectedYt = (wusdAmount * 1050000000000000000000000000000) / 1020000000000000000000000000000; uint256 previewBuyAmount = vault.previewBuy(wusdAmount); assertEq(previewBuyAmount, expectedYt); assertEq(previewBuyAmount, 1029411764705882352941); // 预览卖出 uint256 ytAmount = 1000 * 1e18; uint256 expectedWusd = (ytAmount * 1020000000000000000000000000000) / 1050000000000000000000000000000; uint256 previewSellAmount = vault.previewSell(ytAmount); assertEq(previewSellAmount, expectedWusd); assertEq(previewSellAmount, 971428571428571428571); } function test_37_CanRedeemNow() public { vault = _createVault(); // 赎回时间前 assertFalse(vault.canRedeemNow()); // 赎回时间后 vm.warp(vault.nextRedemptionTime() + 1); assertTrue(vault.canRedeemNow()); } function test_38_GetTimeUntilNextRedemption() public { vault = _createVault(); uint256 redemptionTime = vault.nextRedemptionTime(); uint256 currentTime = block.timestamp; assertEq(vault.getTimeUntilNextRedemption(), redemptionTime - currentTime); // 快进到赎回时间后 vm.warp(redemptionTime + 1); assertEq(vault.getTimeUntilNextRedemption(), 0); } function test_39_CompleteLifecycle() public { vault = _createVault(); // 1. 初始状态验证 assertEq(vault.totalSupply(), 0); assertEq(vault.totalAssets(), 0); // 2. User1和User2存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); vm.startPrank(user2); wusd.approve(address(vault), 5000 * 1e18); vault.depositYT(5000 * 1e18); vm.stopPrank(); assertEq(vault.totalSupply(), 15000 * 1e18); assertEq(vault.totalAssets(), 15000 * 1e18); // 3. Manager提取资金进行投资 vm.prank(manager); vault.withdrawForManagement(manager, 8000 * 1e18); assertEq(vault.managedAssets(), 8000 * 1e18); assertEq(vault.idleAssets(), 7000 * 1e18); assertEq(vault.totalAssets(), 15000 * 1e18); // 4. 价格更新(模拟市场变化) factory.updateVaultPrices( address(vault), 1050000000000000000000000000000, // WUSD涨到1.05 1100000000000000000000000000000 // YT涨到1.10 ); // 5. Manager归还资金+利润 vm.startPrank(manager); wusd.approve(address(vault), 10000 * 1e18); vault.depositManagedAssets(10000 * 1e18); // 归还本金+2000利润 vm.stopPrank(); assertEq(vault.managedAssets(), 0); assertEq(vault.idleAssets(), 17000 * 1e18); // 增加了2000利润 assertEq(vault.totalAssets(), 17000 * 1e18); // 6. 快进到赎回时间 vm.warp(vault.nextRedemptionTime() + 1); // 7. User1提取部分YT uint256 user1YtBalance = vault.balanceOf(user1); uint256 withdrawYtAmount = 5000 * 1e18; vm.startPrank(user1); uint256 wusdReceived = vault.withdrawYT(withdrawYtAmount); vm.stopPrank(); // 按新价格计算: 5000 * 1.10 / 1.05 = 5238.095238095238095238 WUSD uint256 expectedWusd = (withdrawYtAmount * 1100000000000000000000000000000) / 1050000000000000000000000000000; assertEq(wusdReceived, expectedWusd); assertEq(wusdReceived, 5238095238095238095238); // 验证最终状态 assertEq(vault.balanceOf(user1), user1YtBalance - withdrawYtAmount); assertEq(vault.totalSupply(), 10000 * 1e18); } function test_40_PriceFluctuationScenario() public { vault = _createVault(); // 初始存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); uint256 ytReceived1 = vault.depositYT(10000 * 1e18); vm.stopPrank(); assertEq(ytReceived1, 10000 * 1e18); // 1:1 // 价格上涨 factory.updateVaultPrices( address(vault), 1100000000000000000000000000000, // 1.10 1200000000000000000000000000000 // 1.20 ); // User2此时存款,会获得更少的YT vm.startPrank(user2); wusd.approve(address(vault), 10000 * 1e18); uint256 ytReceived2 = vault.depositYT(10000 * 1e18); vm.stopPrank(); // ytAmount = 10000 * 1.10 / 1.20 = 9166.666666666666666666 assertEq(ytReceived2, 9166666666666666666666); // 价格下跌 factory.updateVaultPrices( address(vault), 950000000000000000000000000000, // 0.95 900000000000000000000000000000 // 0.90 ); // 快进到赎回时间 vm.warp(vault.nextRedemptionTime() + 1); // User1提取 vm.startPrank(user1); uint256 wusdBack1 = vault.withdrawYT(ytReceived1); vm.stopPrank(); // wusdAmount = 10000 * 0.90 / 0.95 = 9473.684210526315789473 assertEq(wusdBack1, 9473684210526315789473); // User2提取 vm.startPrank(user2); uint256 wusdBack2 = vault.withdrawYT(ytReceived2); vm.stopPrank(); // wusdAmount = 9166.666... * 0.90 / 0.95 = 8684.210526315789473684 // 允许1 wei的舍入误差 assertApproxEqAbs(wusdBack2, 8684210526315789473684, 1); } // ==================== 暂停功能测试 ==================== function test_41_PauseByFactory() public { vault = _createVault(); // Factory可以暂停 factory.pauseVault(address(vault)); assertTrue(vault.paused(), "vault should be paused"); // Factory可以恢复 factory.unpauseVault(address(vault)); assertFalse(vault.paused(), "vault should be unpaused"); } function test_42_OnlyFactoryCanPause() public { vault = _createVault(); // User不能暂停 vm.startPrank(user1); vm.expectRevert(YTAssetVault.Forbidden.selector); vault.pause(); vm.stopPrank(); // Manager也不能暂停 vm.startPrank(manager); vm.expectRevert(YTAssetVault.Forbidden.selector); vault.pause(); vm.stopPrank(); } function test_43_CannotDepositWhenPaused() public { vault = _createVault(); // 暂停vault factory.pauseVault(address(vault)); // 尝试存款应该失败 vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vm.expectRevert(abi.encodeWithSignature("EnforcedPause()")); vault.depositYT(1000 * 1e18); vm.stopPrank(); // 恢复后应该可以存款 factory.unpauseVault(address(vault)); vm.startPrank(user1); uint256 ytReceived = vault.depositYT(1000 * 1e18); vm.stopPrank(); assertEq(ytReceived, 1000 * 1e18, "deposit should work after unpause"); } function test_44_CannotWithdrawWhenPaused() public { vault = _createVault(); // 先存款 vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); vm.stopPrank(); // 快进到赎回时间 vm.warp(vault.nextRedemptionTime() + 1); // 暂停vault factory.pauseVault(address(vault)); // 尝试提款应该失败 vm.startPrank(user1); vm.expectRevert(abi.encodeWithSignature("EnforcedPause()")); vault.withdrawYT(500 * 1e18); vm.stopPrank(); // 恢复后应该可以提款 factory.unpauseVault(address(vault)); vm.startPrank(user1); uint256 wusdReceived = vault.withdrawYT(500 * 1e18); vm.stopPrank(); assertEq(wusdReceived, 500 * 1e18, "withdraw should work after unpause"); } function test_45_CannotWithdrawForManagementWhenPaused() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); // 暂停vault factory.pauseVault(address(vault)); // Manager尝试提取应该失败 vm.startPrank(manager); vm.expectRevert(abi.encodeWithSignature("EnforcedPause()")); vault.withdrawForManagement(manager, 5000 * 1e18); vm.stopPrank(); // 恢复后应该可以提取 factory.unpauseVault(address(vault)); vm.startPrank(manager); vault.withdrawForManagement(manager, 5000 * 1e18); vm.stopPrank(); assertEq(vault.managedAssets(), 5000 * 1e18, "withdraw for management should work after unpause"); } function test_46_CannotDepositManagedAssetsWhenPaused() public { vault = _createVault(); // 存款并提取 vm.startPrank(user1); wusd.approve(address(vault), 10000 * 1e18); vault.depositYT(10000 * 1e18); vm.stopPrank(); vm.startPrank(manager); vault.withdrawForManagement(manager, 5000 * 1e18); vm.stopPrank(); // 暂停vault factory.pauseVault(address(vault)); // Manager尝试归还应该失败 vm.startPrank(manager); wusd.approve(address(vault), 5000 * 1e18); vm.expectRevert(abi.encodeWithSignature("EnforcedPause()")); vault.depositManagedAssets(5000 * 1e18); vm.stopPrank(); // 恢复后应该可以归还 factory.unpauseVault(address(vault)); vm.startPrank(manager); vault.depositManagedAssets(5000 * 1e18); vm.stopPrank(); assertEq(vault.managedAssets(), 0, "deposit managed assets should work after unpause"); } function test_47_QueryFunctionsWorkWhenPaused() public { vault = _createVault(); // 存款 vm.startPrank(user1); wusd.approve(address(vault), 1000 * 1e18); vault.depositYT(1000 * 1e18); vm.stopPrank(); // 暂停vault factory.pauseVault(address(vault)); // 查询函数应该仍然可用 assertEq(vault.totalSupply(), 1000 * 1e18, "totalSupply should work"); assertEq(vault.balanceOf(user1), 1000 * 1e18, "balanceOf should work"); assertEq(vault.totalAssets(), 1000 * 1e18, "totalAssets should work"); assertEq(vault.idleAssets(), 1000 * 1e18, "idleAssets should work"); // 预览函数应该可用 uint256 previewBuy = vault.previewBuy(100 * 1e18); assertEq(previewBuy, 100 * 1e18, "previewBuy should work"); uint256 previewSell = vault.previewSell(100 * 1e18); assertEq(previewSell, 100 * 1e18, "previewSell should work"); // getVaultInfo应该可用 ( uint256 totalAssets, uint256 idleAssets, ,,,,, ) = vault.getVaultInfo(); assertEq(totalAssets, 1000 * 1e18, "getVaultInfo should work"); assertEq(idleAssets, 1000 * 1e18, "getVaultInfo should work"); } }