Skip to content

Commit fe0d73b

Browse files
committed
finish continuous accounting
1 parent cb72759 commit fe0d73b

File tree

1 file changed

+49
-76
lines changed

1 file changed

+49
-76
lines changed

contracts/tokenbridge/libraries/vault/MasterVault.sol

Lines changed: 49 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)