From 5efe39d8804962eb7778ef6a9cd4a37e3aa76f27 Mon Sep 17 00:00:00 2001 From: Piotr Date: Mon, 20 May 2024 15:25:21 +0200 Subject: [PATCH 1/3] feat: allow for different decimals between fee token and underlying --- src/FlatFeeCalculator.sol | 17 ++- .../FlatFeeCalculator.fuzzy.t.sol | 101 ++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/FlatFeeCalculator.sol b/src/FlatFeeCalculator.sol index c4ac55f..a284e83 100644 --- a/src/FlatFeeCalculator.sol +++ b/src/FlatFeeCalculator.sol @@ -24,6 +24,12 @@ contract FlatFeeCalculator is IFeeCalculator, Ownable { uint256 public feeBasisPoints = 300; + /// @dev The scale between the decimals of the fee token and the underlying token. + /// For example, if the fee token has 18 decimals and the underlying token has 18 decimals, the + /// decimals scale is 1e0. + /// If the fee token has 18 decimals and the underlying token has 0 decimals, the decimals scale is 1e18 + uint256 public feeToUnderlyingDecimalsScale = 1e0; + address[] private _recipients; uint256[] private _shares; @@ -32,6 +38,12 @@ contract FlatFeeCalculator is IFeeCalculator, Ownable { constructor() Ownable() {} + function setFeeToUnderlyingDecimalsScale(uint256 _feeToUnderlyingDecimalsScale) external onlyOwner { + require(_feeToUnderlyingDecimalsScale > 0, "Fee to underlying decimals scale must be greater than 0"); + + feeToUnderlyingDecimalsScale = _feeToUnderlyingDecimalsScale; + } + /// @notice Sets the fee basis points. /// @dev Can only be called by the current owner. /// @param _feeBasisPoints The new fee basis points. @@ -161,9 +173,10 @@ contract FlatFeeCalculator is IFeeCalculator, Ownable { function _calculateFee(uint256 requestedAmount) internal view returns (FeeDistribution memory) { require(requestedAmount > 0, "requested amount must be > 0"); - uint256 feeAmount = requestedAmount * feeBasisPoints / 10000; + uint256 adjustedAmount = requestedAmount * feeToUnderlyingDecimalsScale; + uint256 feeAmount = adjustedAmount * feeBasisPoints / 10000; - require(feeAmount <= requestedAmount, "Fee must be lower or equal to requested amount"); + require(feeAmount <= adjustedAmount, "Fee must be lower or equal to requested amount"); require(feeAmount > 0, "Fee must be greater than 0"); return calculateFeeShares(feeAmount); diff --git a/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol b/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol index 7b2c7a5..0d78d27 100644 --- a/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol +++ b/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol @@ -151,6 +151,21 @@ contract FlatFeeCalculatorTestFuzzy is Test { assertEq(feeDistribution.shares[0], expected); } + function testCalculateDepositFee_withFeeToUnderlyingScale_TCO2(uint256 depositAmount) public { + // Arrange + vm.assume(depositAmount > 1); + vm.assume(depositAmount < 1e18); + + uint256 feeToUnderlyingDecimalsScale = 1e18; + feeCalculator.setFeeToUnderlyingDecimalsScale(feeToUnderlyingDecimalsScale); + // Act + FeeDistribution memory feeDistribution = feeCalculator.calculateDepositFees(empty, empty, depositAmount); + + uint256 expected = depositAmount * feeToUnderlyingDecimalsScale * feeCalculator.feeBasisPoints() / 10000; + + assertEq(feeDistribution.shares[0], expected); + } + function testCalculateDepositFee_ERC1155(uint256 depositAmount) public { // Arrange vm.assume(depositAmount > 100); @@ -163,6 +178,21 @@ contract FlatFeeCalculatorTestFuzzy is Test { assertEq(feeDistribution.shares[0], expected); } + function testCalculateDepositFee_withFeeToUnderlyingScale_ERC1155(uint256 depositAmount) public { + // Arrange + vm.assume(depositAmount > 1); + vm.assume(depositAmount < 1e18); + + uint256 feeToUnderlyingDecimalsScale = 1e18; + feeCalculator.setFeeToUnderlyingDecimalsScale(feeToUnderlyingDecimalsScale); + // Act + FeeDistribution memory feeDistribution = feeCalculator.calculateDepositFees(empty, empty, 0, depositAmount); + + uint256 expected = depositAmount * feeToUnderlyingDecimalsScale * feeCalculator.feeBasisPoints() / 10000; + + assertEq(feeDistribution.shares[0], expected); + } + function testCalculateRedemptionAmount_TCO2( uint256 redemptionAmount1, uint256 redemptionAmount2, @@ -193,6 +223,39 @@ contract FlatFeeCalculatorTestFuzzy is Test { assertEq(feeDistribution.shares[0], expected); } + function testCalculateRedemptionAmount_withFeeToUnderlyingScale_TCO2( + uint256 redemptionAmount1, + uint256 redemptionAmount2, + uint256 redemptionAmount3 + ) public { + // Arrange + vm.assume(redemptionAmount1 > 100); + vm.assume(redemptionAmount1 < 1e18 * 1e18); + vm.assume(redemptionAmount2 > 100); + vm.assume(redemptionAmount2 < 1e18 * 1e18); + vm.assume(redemptionAmount3 > 100); + vm.assume(redemptionAmount3 < 1e18 * 1e18); + + uint256 feeToUnderlyingDecimalsScale = 1e18; + feeCalculator.setFeeToUnderlyingDecimalsScale(feeToUnderlyingDecimalsScale); + // Act + address[] memory tco2s = new address[](3); + tco2s[0] = empty; + tco2s[1] = empty; + tco2s[2] = empty; + uint256[] memory redemptionAmounts = new uint256[](3); + redemptionAmounts[0] = redemptionAmount1; + redemptionAmounts[1] = redemptionAmount2; + redemptionAmounts[2] = redemptionAmount3; + + FeeDistribution memory feeDistribution = feeCalculator.calculateRedemptionFees(empty, tco2s, redemptionAmounts); + + uint256 expected = (redemptionAmount1 + redemptionAmount2 + redemptionAmount3) * feeToUnderlyingDecimalsScale + * feeCalculator.feeBasisPoints() / 10000; + + assertEq(feeDistribution.shares[0], expected); + } + function testCalculateRedemptionAmount_ERC1155( uint256 redemptionAmount1, uint256 redemptionAmount2, @@ -227,4 +290,42 @@ contract FlatFeeCalculatorTestFuzzy is Test { assertEq(feeDistribution.shares[0], expected); } + + function testCalculateRedemptionAmount_withFeeToUnderlyingScale_ERC1155( + uint256 redemptionAmount1, + uint256 redemptionAmount2, + uint256 redemptionAmount3 + ) public { + // Arrange + vm.assume(redemptionAmount1 > 100); + vm.assume(redemptionAmount1 < 1e18 * 1e18); + vm.assume(redemptionAmount2 > 100); + vm.assume(redemptionAmount2 < 1e18 * 1e18); + vm.assume(redemptionAmount3 > 100); + vm.assume(redemptionAmount3 < 1e18 * 1e18); + + uint256 feeToUnderlyingDecimalsScale = 1e18; + feeCalculator.setFeeToUnderlyingDecimalsScale(feeToUnderlyingDecimalsScale); + // Act + address[] memory erc1155s = new address[](3); + erc1155s[0] = empty; + erc1155s[1] = empty; + erc1155s[2] = empty; + uint256[] memory tokenIds = new uint256[](3); + tokenIds[0] = 1; + tokenIds[1] = 2; + tokenIds[2] = 3; + uint256[] memory redemptionAmounts = new uint256[](3); + redemptionAmounts[0] = redemptionAmount1; + redemptionAmounts[1] = redemptionAmount2; + redemptionAmounts[2] = redemptionAmount3; + + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(empty, erc1155s, tokenIds, redemptionAmounts); + + uint256 expected = (redemptionAmount1 + redemptionAmount2 + redemptionAmount3) * feeToUnderlyingDecimalsScale + * feeCalculator.feeBasisPoints() / 10000; + + assertEq(feeDistribution.shares[0], expected); + } } From 48570130fe1263b84845be17ed62409c59ea97e9 Mon Sep 17 00:00:00 2001 From: Piotr Date: Tue, 21 May 2024 09:59:15 +0200 Subject: [PATCH 2/3] chore: set the default value to 1e18 --- src/FlatFeeCalculator.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FlatFeeCalculator.sol b/src/FlatFeeCalculator.sol index a284e83..6679dd0 100644 --- a/src/FlatFeeCalculator.sol +++ b/src/FlatFeeCalculator.sol @@ -28,7 +28,7 @@ contract FlatFeeCalculator is IFeeCalculator, Ownable { /// For example, if the fee token has 18 decimals and the underlying token has 18 decimals, the /// decimals scale is 1e0. /// If the fee token has 18 decimals and the underlying token has 0 decimals, the decimals scale is 1e18 - uint256 public feeToUnderlyingDecimalsScale = 1e0; + uint256 public feeToUnderlyingDecimalsScale = 1e18; address[] private _recipients; uint256[] private _shares; From 57c38e9f760368261f6700c596be78741cd48ace Mon Sep 17 00:00:00 2001 From: Piotr Date: Tue, 21 May 2024 10:20:40 +0200 Subject: [PATCH 3/3] fix: tests after default value for scale change --- test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol b/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol index 0d78d27..834ff41 100644 --- a/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol +++ b/test/FlatFeeCalculatorFuzzy/FlatFeeCalculator.fuzzy.t.sol @@ -22,6 +22,7 @@ contract FlatFeeCalculatorTestFuzzy is Test { uint256[] memory feeShares = new uint256[](1); feeShares[0] = 100; feeCalculator.feeSetup(recipients, feeShares); + feeCalculator.setFeeToUnderlyingDecimalsScale(1); } function testFeeSetupEmpty() public {