|
@@ -4,36 +4,41 @@ pragma solidity ^0.8.0;
|
|
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
|
|
|
|
|
|
+/// @dev ERC4626 vault with entry/exit fees expressed in https://en.wikipedia.org/wiki/Basis_point[basis point (bp)].
|
|
|
abstract contract ERC4626Fees is ERC4626 {
|
|
|
using Math for uint256;
|
|
|
|
|
|
- /** @dev See {IERC4626-previewDeposit}. */
|
|
|
+ uint256 private constant _BASIS_POINT_SCALE = 1e4;
|
|
|
+
|
|
|
+ // === Overrides ===
|
|
|
+
|
|
|
+ /// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}.
|
|
|
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
|
|
|
- uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint());
|
|
|
+ uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
|
|
|
return super.previewDeposit(assets - fee);
|
|
|
}
|
|
|
|
|
|
- /** @dev See {IERC4626-previewMint}. */
|
|
|
+ /// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}.
|
|
|
function previewMint(uint256 shares) public view virtual override returns (uint256) {
|
|
|
uint256 assets = super.previewMint(shares);
|
|
|
- return assets + _feeOnRaw(assets, _entryFeeBasePoint());
|
|
|
+ return assets + _feeOnRaw(assets, _entryFeeBasisPoints());
|
|
|
}
|
|
|
|
|
|
- /** @dev See {IERC4626-previewWithdraw}. */
|
|
|
+ /// @dev Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}.
|
|
|
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
|
|
|
- uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint());
|
|
|
+ uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
|
|
|
return super.previewWithdraw(assets + fee);
|
|
|
}
|
|
|
|
|
|
- /** @dev See {IERC4626-previewRedeem}. */
|
|
|
+ /// @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}.
|
|
|
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
|
|
|
uint256 assets = super.previewRedeem(shares);
|
|
|
- return assets - _feeOnTotal(assets, _exitFeeBasePoint());
|
|
|
+ return assets - _feeOnTotal(assets, _exitFeeBasisPoints());
|
|
|
}
|
|
|
|
|
|
- /** @dev See {IERC4626-_deposit}. */
|
|
|
+ /// @dev Send entry fee to {_entryFeeRecipient}. See {IERC4626-_deposit}.
|
|
|
function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override {
|
|
|
- uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint());
|
|
|
+ uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
|
|
|
address recipient = _entryFeeRecipient();
|
|
|
|
|
|
super._deposit(caller, receiver, assets, shares);
|
|
@@ -43,7 +48,7 @@ abstract contract ERC4626Fees is ERC4626 {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /** @dev See {IERC4626-_deposit}. */
|
|
|
+ /// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}.
|
|
|
function _withdraw(
|
|
|
address caller,
|
|
|
address receiver,
|
|
@@ -51,7 +56,7 @@ abstract contract ERC4626Fees is ERC4626 {
|
|
|
uint256 assets,
|
|
|
uint256 shares
|
|
|
) internal virtual override {
|
|
|
- uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint());
|
|
|
+ uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
|
|
|
address recipient = _exitFeeRecipient();
|
|
|
|
|
|
super._withdraw(caller, receiver, owner, assets, shares);
|
|
@@ -61,27 +66,35 @@ abstract contract ERC4626Fees is ERC4626 {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- function _entryFeeBasePoint() internal view virtual returns (uint256) {
|
|
|
- return 0;
|
|
|
+ // === Fee configuration ===
|
|
|
+
|
|
|
+ function _entryFeeBasisPoints() internal view virtual returns (uint256) {
|
|
|
+ return 0; // replace with e.g. 100 for 1%
|
|
|
}
|
|
|
|
|
|
- function _entryFeeRecipient() internal view virtual returns (address) {
|
|
|
- return address(0);
|
|
|
+ function _exitFeeBasisPoints() internal view virtual returns (uint256) {
|
|
|
+ return 0; // replace with e.g. 100 for 1%
|
|
|
}
|
|
|
|
|
|
- function _exitFeeBasePoint() internal view virtual returns (uint256) {
|
|
|
- return 0;
|
|
|
+ function _entryFeeRecipient() internal view virtual returns (address) {
|
|
|
+ return address(0); // replace with e.g. a treasury address
|
|
|
}
|
|
|
|
|
|
function _exitFeeRecipient() internal view virtual returns (address) {
|
|
|
- return address(0);
|
|
|
+ return address(0); // replace with e.g. a treasury address
|
|
|
}
|
|
|
|
|
|
- function _feeOnRaw(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) {
|
|
|
- return assets.mulDiv(feeBasePoint, 1e5, Math.Rounding.Up);
|
|
|
+ // === Fee operations ===
|
|
|
+
|
|
|
+ /// @dev Calculates the fees that should be added to an amount `assets` that does not already include fees.
|
|
|
+ /// Used in {IERC4626-mint} and {IERC4626-withdraw} operations.
|
|
|
+ function _feeOnRaw(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
|
|
|
+ return assets.mulDiv(feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Up);
|
|
|
}
|
|
|
|
|
|
- function _feeOnTotal(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) {
|
|
|
- return assets.mulDiv(feeBasePoint, feeBasePoint + 1e5, Math.Rounding.Up);
|
|
|
+ /// @dev Calculates the fee part of an amount `assets` that already includes fees.
|
|
|
+ /// Used in {IERC4626-deposit} and {IERC4626-redeem} operations.
|
|
|
+ function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
|
|
|
+ return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Up);
|
|
|
}
|
|
|
}
|