ERC4626Fees.sol 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {IERC20} from "../../token/ERC20/IERC20.sol";
  4. import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol";
  5. import {SafeERC20} from "../../token/ERC20/utils/SafeERC20.sol";
  6. import {Math} from "../../utils/math/Math.sol";
  7. /// @dev ERC-4626 vault with entry/exit fees expressed in https://en.wikipedia.org/wiki/Basis_point[basis point (bp)].
  8. abstract contract ERC4626Fees is ERC4626 {
  9. using Math for uint256;
  10. uint256 private constant _BASIS_POINT_SCALE = 1e4;
  11. // === Overrides ===
  12. /// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}.
  13. function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
  14. uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
  15. return super.previewDeposit(assets - fee);
  16. }
  17. /// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}.
  18. function previewMint(uint256 shares) public view virtual override returns (uint256) {
  19. uint256 assets = super.previewMint(shares);
  20. return assets + _feeOnRaw(assets, _entryFeeBasisPoints());
  21. }
  22. /// @dev Preview adding an exit fee on withdraw. See {IERC4626-previewWithdraw}.
  23. function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
  24. uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
  25. return super.previewWithdraw(assets + fee);
  26. }
  27. /// @dev Preview taking an exit fee on redeem. See {IERC4626-previewRedeem}.
  28. function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
  29. uint256 assets = super.previewRedeem(shares);
  30. return assets - _feeOnTotal(assets, _exitFeeBasisPoints());
  31. }
  32. /// @dev Send entry fee to {_entryFeeRecipient}. See {IERC4626-_deposit}.
  33. function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override {
  34. uint256 fee = _feeOnTotal(assets, _entryFeeBasisPoints());
  35. address recipient = _entryFeeRecipient();
  36. super._deposit(caller, receiver, assets, shares);
  37. if (fee > 0 && recipient != address(this)) {
  38. SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
  39. }
  40. }
  41. /// @dev Send exit fee to {_exitFeeRecipient}. See {IERC4626-_deposit}.
  42. function _withdraw(
  43. address caller,
  44. address receiver,
  45. address owner,
  46. uint256 assets,
  47. uint256 shares
  48. ) internal virtual override {
  49. uint256 fee = _feeOnRaw(assets, _exitFeeBasisPoints());
  50. address recipient = _exitFeeRecipient();
  51. super._withdraw(caller, receiver, owner, assets, shares);
  52. if (fee > 0 && recipient != address(this)) {
  53. SafeERC20.safeTransfer(IERC20(asset()), recipient, fee);
  54. }
  55. }
  56. // === Fee configuration ===
  57. function _entryFeeBasisPoints() internal view virtual returns (uint256) {
  58. return 0; // replace with e.g. 100 for 1%
  59. }
  60. function _exitFeeBasisPoints() internal view virtual returns (uint256) {
  61. return 0; // replace with e.g. 100 for 1%
  62. }
  63. function _entryFeeRecipient() internal view virtual returns (address) {
  64. return address(0); // replace with e.g. a treasury address
  65. }
  66. function _exitFeeRecipient() internal view virtual returns (address) {
  67. return address(0); // replace with e.g. a treasury address
  68. }
  69. // === Fee operations ===
  70. /// @dev Calculates the fees that should be added to an amount `assets` that does not already include fees.
  71. /// Used in {IERC4626-mint} and {IERC4626-withdraw} operations.
  72. function _feeOnRaw(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
  73. return assets.mulDiv(feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Ceil);
  74. }
  75. /// @dev Calculates the fee part of an amount `assets` that already includes fees.
  76. /// Used in {IERC4626-deposit} and {IERC4626-redeem} operations.
  77. function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
  78. return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Ceil);
  79. }
  80. }