The fees charged to the feeRecipient
are inconsistent between functions deposit
and mint
Description
Users can choose to use either the function deposit
or the function mint
to deposit an asset to the vault. However, the methods by which functions deposit
and mint
charge the feeRecipient
are inconsistent. The function deposit
does not charge a deposit fee when the caller is the feeRecipient
, while the function mint
always charges a deposit fee regardless of the caller.
function deposit(uint256 assets_, address receiver_)
// [...]
returns (uint256 shares)
{
// [...]
// Calculate shares based on whether sender is fee recipient
if (msg.sender == feeRecipient) {
shares = _convertToShares(assets_, Math.Rounding.Floor);
} else {
// Calculate the fee in shares
uint256 feeShares = _convertToShares(
assets_.mulDiv(uint256(fees.depositFee), MAX_BASIS_POINTS, Math.Rounding.Ceil), Math.Rounding.Ceil
);
// Calculate the net shares to mint for the deposited assets
shares = _convertToShares(assets_, Math.Rounding.Floor) - feeShares;
// Mint fee shares to fee recipient
if (feeShares > 0) _mint(feeRecipient, feeShares);
}
// [...]
}
function mint(uint256 shares_, address receiver_)
// [...]
returns (uint256 assets)
{
// [...]
// Calculate the deposit fee in shares
uint256 depositFee = uint256(fees.depositFee);
uint256 feeShares =
shares_.mulDiv(MAX_BASIS_POINTS, MAX_BASIS_POINTS - depositFee, Math.Rounding.Ceil) - shares_;
// Calculate the total assets required for the minted shares, including fees
assets = _convertToAssets(shares_ + feeShares, Math.Rounding.Ceil);
// [...]
}
Impact
If the feeRecipient
is depositing on behalf of a receiver, then, using the same amount of the asset, the receiver will receive more shares if the function deposit
is used.
Recommendations
Consider unifying the way these two functions charge the feeRecipient
and updating functions previewDeposit
and previewMint
accordingly.
Remediation
This issue has been acknowledged by Blueprint Finance, and fixes were implemented in the following commits: