@@ -83,31 +83,6 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
8383 _grantRole (PAUSER_ROLE, _owner);
8484 }
8585
86-
87- function deposit (uint256 assets , address receiver , uint256 minSharesMinted ) public returns (uint256 ) {
88- uint256 shares = deposit (assets, receiver);
89- if (shares < minSharesMinted) revert TooFewSharesReceived ();
90- return shares;
91- }
92-
93- function withdraw (uint256 assets , address receiver , address _owner , uint256 maxSharesBurned ) public returns (uint256 ) {
94- uint256 shares = withdraw (assets, receiver, _owner);
95- if (shares > maxSharesBurned) revert TooManySharesBurned ();
96- return shares;
97- }
98-
99- function mint (uint256 shares , address receiver , uint256 maxAssetsDeposited ) public returns (uint256 ) {
100- uint256 assets = super .mint (shares, receiver);
101- if (assets > maxAssetsDeposited) revert TooManyAssetsDeposited ();
102- return assets;
103- }
104-
105- function redeem (uint256 shares , address receiver , address _owner , uint256 minAssetsReceived ) public returns (uint256 ) {
106- uint256 assets = super .redeem (shares, receiver, _owner);
107- if (assets < minAssetsReceived) revert TooFewAssetsReceived ();
108- return assets;
109- }
110-
11186 /// @notice Set a subvault. Can only be called if there is not already a subvault set.
11287 /// @param _subVault The subvault to set. Must be an ERC4626 vault with the same asset as this MasterVault.
11388 /// @param minSubVaultExchRateWad Minimum acceptable ratio (times 1e18) of new subvault shares to outstanding MasterVault shares after deposit.
@@ -147,7 +122,12 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
147122 /// @notice Toggle performance fee collection on/off
148123 /// @param enabled True to enable performance fees, false to disable
149124 function setPerformanceFee (bool enabled ) external onlyRole (VAULT_MANAGER_ROLE) {
150- enablePerformanceFee = enabled; // todo: this should set totalPrincipal to current totalAssets() to avoid sudden fee realization
125+ enablePerformanceFee = enabled;
126+ // reset totalPrincipal to current totalAssets when enabling performance fee
127+ // this prevents a sudden large profit
128+ if (enabled) {
129+ totalPrincipal = _totalAssets (MathUpgradeable.Rounding.Up);
130+ }
151131 emit PerformanceFeeToggled (enabled);
152132 }
153133
@@ -169,11 +149,14 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
169149
170150 /** @dev See {IERC4626-totalAssets}. */
171151 function totalAssets () public view virtual override returns (uint256 ) {
172- IERC4626 _subVault = subVault;
173- if (address (_subVault) == address (0 )) {
152+ return _totalAssets (MathUpgradeable.Rounding.Down);
153+ }
154+
155+ function _totalAssets (MathUpgradeable.Rounding rounding ) internal view returns (uint256 ) {
156+ if (address (subVault) == address (0 )) {
174157 return IERC20 (asset ()).balanceOf (address (this ));
175158 }
176- return _subVault. convertToAssets (_subVault .balanceOf (address (this )));
159+ return _subVaultSharesToAssets (subVault .balanceOf (address (this )), rounding );
177160 }
178161
179162 /** @dev See {IERC4626-maxDeposit}. */
@@ -185,16 +168,16 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
185168 }
186169
187170 // /** @dev See {IERC4626-maxMint}. */
188- // function maxMint(address) public view virtual override returns (uint256) {
189- // if (address(subVault) == address(0)) {
190- // return type(uint256).max;
191- // }
192- // uint256 subShares = subVault.maxMint(address(this));
193- // if (subShares == type(uint256).max) {
194- // return type(uint256).max;
195- // }
196- // return subSharesToMasterShares( subShares, MathUpgradeable.Rounding.Down);
197- // }
171+ function maxMint (address ) public view virtual override returns (uint256 ) {
172+ if (address (subVault) == address (0 )) {
173+ return type (uint256 ).max;
174+ }
175+ uint256 subShares = subVault.maxMint (address (this ));
176+ if (subShares == type (uint256 ).max) {
177+ return type (uint256 ).max;
178+ }
179+ return totalSupply (). mulDiv ( subShares, subVault. balanceOf ( address ( this )), MathUpgradeable.Rounding.Down); // todo: check rounding direction
180+ }
198181
199182 /**
200183 * @dev Internal conversion function (from assets to shares) with support for rounding direction.
@@ -203,42 +186,35 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
203186 * would represent an infinite amount of shares.
204187 */
205188 function _convertToShares (uint256 assets , MathUpgradeable.Rounding rounding ) internal view virtual override returns (uint256 shares ) {
206- IERC4626 _subVault = subVault;
207- uint256 _totalPrincipal = totalPrincipal;
208- uint256 _totalSupply = totalSupply ();
209-
210- if (address (_subVault) == address (0 )) {
211- uint256 effectiveTotalAssets = enablePerformanceFee ? _min (totalAssets (), _totalPrincipal) : totalAssets ();
212- return _totalSupply.mulDiv (assets, effectiveTotalAssets, rounding);
189+ if (address (subVault) == address (0 )) {
190+ uint256 effectiveTotalAssets = enablePerformanceFee ? _min (totalAssets (), totalPrincipal) : totalAssets ();
191+ return totalSupply ().mulDiv (assets, effectiveTotalAssets, rounding);
213192 }
214193
215- uint256 subShares = _assetsToSubVaultShares (_subVault, assets, rounding);
216- uint256 totalSubShares = _subVault.balanceOf (address (this ));
194+ uint256 totalSubShares = subVault.balanceOf (address (this ));
217195
218196 if (enablePerformanceFee) {
219197 // since we use totalSubShares in the denominator of the final calculation,
220198 // and we are subtracting profit from it, we should use the same rounding direction for profit
221199 totalSubShares -= totalProfitInSubVaultShares (_flipRounding (rounding));
222200 }
201+
202+ uint256 subShares = _assetsToSubVaultShares (assets, rounding);
223203
224- return _totalSupply .mulDiv (subShares, totalSubShares, rounding);
204+ return totalSupply () .mulDiv (subShares, totalSubShares, rounding);
225205 }
226206
227207 /**
228208 * @dev Internal conversion function (from shares to assets) with support for rounding direction.
229209 */
230210 function _convertToAssets (uint256 shares , MathUpgradeable.Rounding rounding ) internal view virtual override returns (uint256 assets ) {
231- IERC4626 _subVault = subVault;
232- uint256 _totalPrincipal = totalPrincipal;
233- uint256 _totalSupply = totalSupply ();
234-
235211 // if we have no subvault, we just do normal pro-rata calculation
236- if (address (_subVault ) == address (0 )) {
237- uint256 effectiveTotalAssets = enablePerformanceFee ? _min (totalAssets (), _totalPrincipal ) : totalAssets ();
238- return effectiveTotalAssets.mulDiv (shares, _totalSupply , rounding);
212+ if (address (subVault ) == address (0 )) {
213+ uint256 effectiveTotalAssets = enablePerformanceFee ? _min (totalAssets (), totalPrincipal ) : totalAssets ();
214+ return effectiveTotalAssets.mulDiv (shares, totalSupply () , rounding);
239215 }
240216
241- uint256 totalSubShares = _subVault .balanceOf (address (this ));
217+ uint256 totalSubShares = subVault .balanceOf (address (this ));
242218
243219 if (enablePerformanceFee) {
244220 // since we use totalSubShares in the numerator of the final calculation,
@@ -247,17 +223,17 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
247223 }
248224
249225 // totalSubShares * shares / totalMasterShares
250- uint256 subShares = totalSubShares.mulDiv (shares, _totalSupply , rounding);
226+ uint256 subShares = totalSubShares.mulDiv (shares, totalSupply () , rounding);
251227
252- return _subVaultSharesToAssets (_subVault, subShares, rounding);
228+ return _subVaultSharesToAssets (subShares, rounding);
253229 }
254230
255- function _assetsToSubVaultShares (IERC4626 _subVault , uint256 assets , MathUpgradeable.Rounding rounding ) internal view returns (uint256 subShares ) {
256- return rounding == MathUpgradeable.Rounding.Up ? _subVault .previewWithdraw (assets) : _subVault .previewDeposit (assets);
231+ function _assetsToSubVaultShares (uint256 assets , MathUpgradeable.Rounding rounding ) internal view returns (uint256 subShares ) {
232+ return rounding == MathUpgradeable.Rounding.Up ? subVault .previewWithdraw (assets) : subVault .previewDeposit (assets);
257233 }
258234
259- function _subVaultSharesToAssets (IERC4626 _subVault , uint256 subShares , MathUpgradeable.Rounding rounding ) internal view returns (uint256 assets ) {
260- return rounding == MathUpgradeable.Rounding.Up ? _subVault .previewMint (subShares) : _subVault .previewRedeem (subShares);
235+ function _subVaultSharesToAssets (uint256 subShares , MathUpgradeable.Rounding rounding ) internal view returns (uint256 assets ) {
236+ return rounding == MathUpgradeable.Rounding.Up ? subVault .previewMint (subShares) : subVault .previewRedeem (subShares);
261237 }
262238
263239 function _min (uint256 a , uint256 b ) internal pure returns (uint256 ) {
@@ -268,29 +244,20 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
268244 return rounding == MathUpgradeable.Rounding.Up ? MathUpgradeable.Rounding.Down : MathUpgradeable.Rounding.Up;
269245 }
270246
271-
272247 function totalProfit (MathUpgradeable.Rounding rounding ) public view returns (uint256 ) {
273- IERC4626 _subVault = subVault;
274- if (address (_subVault) == address (0 )) {
275- uint256 _tokenBalance = IERC20 (asset ()).balanceOf (address (this ));
276- return _tokenBalance > totalPrincipal ? _tokenBalance - totalPrincipal : 0 ;
277- }
278- uint256 totalSubShares = _subVault.balanceOf (address (this ));
279- uint256 _totalAssets = _subVaultSharesToAssets (_subVault, totalSubShares, rounding);
280- uint256 _totalPrincipal = totalPrincipal;
281- return _totalAssets > _totalPrincipal ? _totalAssets - _totalPrincipal : 0 ;
248+ uint256 __totalAssets = _totalAssets (rounding);
249+ return __totalAssets > totalPrincipal ? __totalAssets - totalPrincipal : 0 ;
282250 }
283251
284252 function totalProfitInSubVaultShares (MathUpgradeable.Rounding rounding ) public view returns (uint256 ) {
285- IERC4626 _subVault = subVault;
286- if (address (_subVault) == address (0 )) {
253+ if (address (subVault) == address (0 )) {
287254 revert ("Subvault not set " );
288255 }
289256 uint256 profitAssets = totalProfit (rounding);
290257 if (profitAssets == 0 ) {
291258 return 0 ;
292259 }
293- return _assetsToSubVaultShares (_subVault, profitAssets, rounding);
260+ return _assetsToSubVaultShares (profitAssets, rounding);
294261 }
295262
296263 /**
@@ -330,4 +297,10 @@ contract MasterVault is Initializable, ERC4626Upgradeable, AccessControlUpgradea
330297
331298 super ._withdraw (caller, receiver, _owner, assets, shares);
332299 }
300+
301+ function distributePerformanceFee () external whenNotPaused {
302+ if (! enablePerformanceFee) revert PerformanceFeeDisabled ();
303+ subVault.redeem (totalProfitInSubVaultShares (MathUpgradeable.Rounding.Down), beneficiary, address (this ));
304+ // todo emit event
305+ }
333306}
0 commit comments