@@ -5,145 +5,176 @@ import { MasterVaultCoreTest } from "./MasterVaultCore.t.sol";
55import { MockSubVault } from "../../../contracts/tokenbridge/test/MockSubVault.sol " ;
66import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
77import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol " ;
8+ import { Math } from "@openzeppelin/contracts/utils/math/Math.sol " ;
9+ import {console2} from "forge-std/console2.sol " ;
10+
11+ contract MasterVaultFirstDepositTest is MasterVaultCoreTest {
12+ using Math for uint256 ;
13+
14+ uint256 constant FRESH_STATE_PLACEHOLDER = uint256 (keccak256 ("FRESH_STATE_PLACEHOLDER " ));
15+ uint256 constant DEAD_SHARES = 10 ** 18 ;
16+
17+ struct State {
18+ uint256 userShares;
19+ uint256 masterVaultTotalAssets;
20+ uint256 masterVaultTotalSupply;
21+ uint256 masterVaultTokenBalance;
22+ uint256 masterVaultSubVaultShareBalance;
23+ uint256 subVaultTotalAssets;
24+ uint256 subVaultTotalSupply;
25+ uint256 subVaultTokenBalance;
26+ }
827
9- contract MasterVaultTest is MasterVaultCoreTest {
1028 // first deposit
11- function test_deposit () public {
12- address _assetsHoldingVault = address (vault.subVault ()) == address (0 )
13- ? address (vault)
14- : address (vault.subVault ());
15- uint256 _assetsHoldingVaultBalanceBefore = token.balanceOf (_assetsHoldingVault);
16-
29+ function test_deposit (uint96 _depositAmount ) public {
30+ uint256 depositAmount = _depositAmount;
1731 vm.startPrank (user);
18- token.mint ();
19- uint256 depositAmount = 100 ;
20-
32+ token.mint (depositAmount);
2133 token.approve (address (vault), depositAmount);
22-
2334 uint256 shares = vault.deposit (depositAmount, user);
24-
25- uint256 _assetsHoldingVaultBalanceAfter = token.balanceOf (_assetsHoldingVault);
26- uint256 diff = _assetsHoldingVaultBalanceAfter - _assetsHoldingVaultBalanceBefore;
27-
28- assertEq (vault.balanceOf (user), shares, "User should receive shares " );
29- assertEq (vault.totalAssets (), depositAmount, "Vault should hold deposited assets " );
30- assertEq (vault.totalSupply (), shares, "Total supply should equal shares minted " );
31-
32- assertEq (diff, depositAmount, "Vault should increase holding of assets " );
33- assertGt (token.balanceOf (_assetsHoldingVault), 0 , "Vault should hold the tokens " );
34-
35- assertEq (vault.totalSupply (), diff, "First deposit should be at a rate of 1 " );
36-
3735 vm.stopPrank ();
36+ _checkState (State ({
37+ userShares: depositAmount * DEAD_SHARES,
38+ masterVaultTotalAssets: depositAmount,
39+ masterVaultTotalSupply: (1 + depositAmount) * DEAD_SHARES,
40+ masterVaultTokenBalance: depositAmount,
41+ masterVaultSubVaultShareBalance: 0 ,
42+ subVaultTotalAssets: 0 ,
43+ subVaultTotalSupply: 0 ,
44+ subVaultTokenBalance: 0
45+ }));
46+ assertEq (shares, depositAmount * DEAD_SHARES, "shares mismatch deposit return value " );
3847 }
3948
40- // first mint
41- function test_mint () public {
42- address _assetsHoldingVault = address (vault.subVault ()) == address (0 )
43- ? address (vault)
44- : address (vault.subVault ());
45-
46- uint256 _assetsHoldingVaultBalanceBefore = token.balanceOf (_assetsHoldingVault);
47-
49+ function test_mint (uint96 _mintAmount ) public {
50+ uint256 mintAmount = _mintAmount;
4851 vm.startPrank (user);
49- token.mint ();
50- uint256 sharesToMint = 100 ;
51-
52- token.approve (address (vault), type (uint256 ).max);
53-
54- // assertEq(1, vault.totalAssets(), "First mint should be at a rate of 1"); // 0
55- // assertEq(1, vault.totalSupply(), "First mint should be at a rate of 1"); // 0
56-
57-
58- uint256 assetsCost = vault.mint (sharesToMint, user);
59-
60- uint256 _assetsHoldingVaultBalanceAfter = token.balanceOf (_assetsHoldingVault);
61-
62- assertEq (vault.balanceOf (user), sharesToMint, "User should receive requested shares " );
63- assertEq (vault.totalSupply (), sharesToMint, "Total supply should equal shares minted " );
64- assertEq (vault.totalAssets (), assetsCost, "Vault should hold the assets deposited " );
65- assertEq (
66- _assetsHoldingVaultBalanceAfter - _assetsHoldingVaultBalanceBefore,
67- assetsCost,
68- "Vault should hold the tokens "
69- );
70-
71- assertEq (vault.totalSupply (), vault.totalAssets (), "First mint should be at a rate of 1 " );
52+ token.mint (mintAmount);
53+ token.approve (address (vault), mintAmount);
54+ uint256 assets = vault.mint (mintAmount, user);
7255 vm.stopPrank ();
56+ _checkState (State ({
57+ userShares: mintAmount,
58+ masterVaultTotalAssets: mintAmount.ceilDiv (1e18 ),
59+ masterVaultTotalSupply: mintAmount + DEAD_SHARES,
60+ masterVaultTokenBalance: mintAmount.ceilDiv (1e18 ),
61+ masterVaultSubVaultShareBalance: 0 ,
62+ subVaultTotalAssets: 0 ,
63+ subVaultTotalSupply: 0 ,
64+ subVaultTokenBalance: 0
65+ }));
66+ assertEq (assets, mintAmount.ceilDiv (1e18 ), "assets mismatch mint return value " );
7367 }
7468
75- function test_withdraw () public {
69+ function test_withdraw (uint96 _firstDeposit , uint96 _withdrawAmount ) public {
70+ uint256 firstDeposit = _firstDeposit;
71+ uint256 withdrawAmount = _withdrawAmount;
72+ vm.assume (withdrawAmount <= firstDeposit);
73+ test_deposit (_firstDeposit);
7674 vm.startPrank (user);
77- token.mint ();
78- uint256 depositAmount = token.balanceOf (user);
79- token.approve (address (vault), depositAmount);
80- vault.deposit (depositAmount, user);
81-
82- uint256 userSharesBefore = vault.balanceOf (user);
83- uint256 withdrawAmount = depositAmount; // withdraw all assets
84-
8575 uint256 sharesRedeemed = vault.withdraw (withdrawAmount, user, user);
86-
87- assertEq (vault.balanceOf (user), 0 , "User should have no shares left " );
88- assertEq (token.balanceOf (user), depositAmount, "User should receive all withdrawn tokens " );
89- assertEq (vault.totalAssets (), 0 , "Vault should have no assets left " );
90- assertEq (vault.totalSupply (), 0 , "Total supply should be zero " );
91- assertEq (token.balanceOf (address (vault)), 0 , "Vault should have no tokens left " );
92- assertEq (sharesRedeemed, userSharesBefore, "All shares should be redeemed " );
93-
9476 vm.stopPrank ();
77+ _checkState (State ({
78+ userShares: (firstDeposit - withdrawAmount) * DEAD_SHARES,
79+ masterVaultTotalAssets: firstDeposit - withdrawAmount,
80+ masterVaultTotalSupply: (1 + firstDeposit - withdrawAmount) * DEAD_SHARES,
81+ masterVaultTokenBalance: firstDeposit - withdrawAmount,
82+ masterVaultSubVaultShareBalance: 0 ,
83+ subVaultTotalAssets: 0 ,
84+ subVaultTotalSupply: 0 ,
85+ subVaultTokenBalance: 0
86+ }));
87+ assertEq (sharesRedeemed, withdrawAmount * DEAD_SHARES, "sharesRedeemed mismatch withdraw return value " );
9588 }
9689
97- function test_redeem () public {
90+ function test_redeem (uint96 _firstMint , uint96 _redeemAmount ) public {
91+ uint256 firstMint = _firstMint;
92+ uint256 redeemAmount = _redeemAmount;
93+ vm.assume (redeemAmount <= firstMint);
94+ test_mint (_firstMint);
95+ State memory beforeState = _getState ();
9896 vm.startPrank (user);
99- token.mint ();
100- uint256 depositAmount = token.balanceOf (user);
101- token.approve (address (vault), depositAmount);
102- uint256 shares = vault.deposit (depositAmount, user);
103-
104- uint256 sharesToRedeem = shares; // redeem all shares
105-
106- uint256 assetsReceived = vault.redeem (sharesToRedeem, user, user);
107-
108- assertEq (vault.balanceOf (user), 0 , "User should have no shares left " );
109- assertEq (token.balanceOf (user), depositAmount, "User should receive all assets back " );
110- assertEq (vault.totalAssets (), 0 , "Vault should have no assets left " );
111- assertEq (vault.totalSupply (), 0 , "Total supply should be zero " );
112- assertEq (token.balanceOf (address (vault)), 0 , "Vault should have no tokens left " );
113- assertEq (assetsReceived, depositAmount, "All assets should be received " );
114-
97+ uint256 assets = vault.redeem (redeemAmount, user, user);
98+ uint256 expectedAssets = (1 + beforeState.masterVaultTotalAssets) * redeemAmount / (beforeState.masterVaultTotalSupply);
11599 vm.stopPrank ();
100+ _checkState (State ({
101+ userShares: beforeState.userShares - redeemAmount,
102+ masterVaultTotalAssets: beforeState.masterVaultTotalAssets - expectedAssets,
103+ masterVaultTotalSupply: beforeState.masterVaultTotalSupply - redeemAmount,
104+ masterVaultTokenBalance: beforeState.masterVaultTokenBalance - expectedAssets,
105+ masterVaultSubVaultShareBalance: 0 ,
106+ subVaultTotalAssets: 0 ,
107+ subVaultTotalSupply: 0 ,
108+ subVaultTokenBalance: 0
109+ }));
110+ assertEq (assets, expectedAssets, "assets mismatch redeem return value " );
116111 }
117- }
118112
119- contract MasterVaultTestWithSubvaultFresh is MasterVaultTest {
120- function setUp () public override {
121- super .setUp ();
122- MockSubVault _subvault = new MockSubVault (IERC20 (address (token)), "TestSubvault " , "TSV " );
123- vault.setSubVault (IERC4626 (address (_subvault)), 0 );
113+ function _checkState (State memory expectedState ) internal {
114+ assertEq (expectedState.userShares, vault.balanceOf (user), "userShares mismatch " );
115+ assertEq (expectedState.masterVaultTotalAssets, vault.totalAssets (), "masterVaultTotalAssets mismatch " );
116+ assertEq (expectedState.masterVaultTotalSupply, vault.totalSupply (), "masterVaultTotalSupply mismatch " );
117+ assertEq (expectedState.masterVaultTokenBalance, token.balanceOf (address (vault)), "masterVaultTokenBalance mismatch " );
118+ assertEq (expectedState.masterVaultSubVaultShareBalance, vault.subVault ().balanceOf (address (vault)), "masterVaultSubVaultShareBalance mismatch " );
119+ assertEq (expectedState.subVaultTotalAssets, vault.subVault ().totalAssets (), "subVaultTotalAssets mismatch " );
120+ assertEq (expectedState.subVaultTotalSupply, vault.subVault ().totalSupply (), "subVaultTotalSupply mismatch " );
121+ assertEq (expectedState.subVaultTokenBalance, token.balanceOf (address (vault.subVault ())), "subVaultTokenBalance mismatch " );
124122 }
125- }
126-
127- contract MasterVaultTestWithSubvaultHoldingAssets is MasterVaultTest {
128- function setUp () public override {
129- super .setUp ();
130123
131- MockSubVault _subvault = new MockSubVault (IERC20 (address (token)), "TestSubvault " , "TSV " );
132- uint256 _initAmount = 97659743 ;
133- token.mint (_initAmount);
134- token.approve (address (_subvault), _initAmount);
135- _subvault.deposit (_initAmount, address (this ));
136- assertEq (
137- _initAmount,
138- _subvault.totalAssets (),
139- "subvault should be initiated with assets = _initAmount "
140- );
141- assertEq (
142- _initAmount,
143- _subvault.totalSupply (),
144- "subvault should be initiated with shares = _initAmount "
145- );
124+ function _getState () internal view returns (State memory ) {
125+ return State ({
126+ userShares: vault.balanceOf (user),
127+ masterVaultTotalAssets: vault.totalAssets (),
128+ masterVaultTotalSupply: vault.totalSupply (),
129+ masterVaultTokenBalance: token.balanceOf (address (vault)),
130+ masterVaultSubVaultShareBalance: vault.subVault ().balanceOf (address (vault)),
131+ subVaultTotalAssets: vault.subVault ().totalAssets (),
132+ subVaultTotalSupply: vault.subVault ().totalSupply (),
133+ subVaultTokenBalance: token.balanceOf (address (vault.subVault ()))
134+ });
135+ }
146136
147- vault.setSubVault (IERC4626 (address (_subvault)), 0 );
137+ function _logState (string memory label , State memory state ) internal view {
138+ console2.log (label);
139+ console2.log (" userShares: " , state.userShares);
140+ console2.log (" masterVaultTotalAssets: " , state.masterVaultTotalAssets);
141+ console2.log (" masterVaultTotalSupply: " , state.masterVaultTotalSupply);
142+ console2.log (" masterVaultTokenBalance: " , state.masterVaultTokenBalance);
143+ console2.log (" masterVaultSubVaultShareBalance: " , state.masterVaultSubVaultShareBalance);
144+ console2.log (" subVaultTotalAssets: " , state.subVaultTotalAssets);
145+ console2.log (" subVaultTotalSupply: " , state.subVaultTotalSupply);
146+ console2.log (" subVaultTokenBalance: " , state.subVaultTokenBalance);
148147 }
149148}
149+
150+ // contract MasterVaultTestWithSubvaultFresh is MasterVaultTest {
151+ // function setUp() public override {
152+ // super.setUp();
153+ // MockSubVault _subvault = new MockSubVault(IERC20(address(token)), "TestSubvault", "TSV");
154+ // vault.setSubVault(IERC4626(address(_subvault)));
155+ // }
156+ // }
157+
158+ // contract MasterVaultTestWithSubvaultHoldingAssets is MasterVaultTest {
159+ // function setUp() public override {
160+ // super.setUp();
161+
162+ // MockSubVault _subvault = new MockSubVault(IERC20(address(token)), "TestSubvault", "TSV");
163+ // uint256 _initAmount = 97659743;
164+ // token.mint(_initAmount);
165+ // token.approve(address(_subvault), _initAmount);
166+ // _subvault.deposit(_initAmount, address(this));
167+ // assertEq(
168+ // _initAmount,
169+ // _subvault.totalAssets(),
170+ // "subvault should be initiated with assets = _initAmount"
171+ // );
172+ // assertEq(
173+ // _initAmount,
174+ // _subvault.totalSupply(),
175+ // "subvault should be initiated with shares = _initAmount"
176+ // );
177+
178+ // vault.setSubVault(IERC4626(address(_subvault)));
179+ // }
180+ // }
0 commit comments