diff --git a/src/FeeCalculator.sol b/src/FeeCalculator.sol index be322e2..2bb57cf 100644 --- a/src/FeeCalculator.sol +++ b/src/FeeCalculator.sol @@ -9,7 +9,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import {SD59x18, sd, intoUint256} from "@prb/math/src/SD59x18.sol"; -import "./interfaces/IFeeCalculator.sol"; +import {IFeeCalculator, FeeDistribution} from "./interfaces/IFeeCalculator.sol"; import "./interfaces/IPool.sol"; /// @title FeeCalculator @@ -136,86 +136,65 @@ contract FeeCalculator is IFeeCalculator, Ownable { /// @param tco2 The address of the TCO2 token. /// @param pool The address of the pool. /// @param depositAmount The amount to be deposited. - /// @return feeAmount The fee to be charged in pool - /// tokens for this deposit. + /// @return feeDistribution How the fee is meant to be + /// distributed among the fee recipients. function calculateDepositFees(address tco2, address pool, uint256 depositAmount) external view override - returns (uint256 feeAmount) + returns (FeeDistribution memory feeDistribution) { require(depositAmount > 0, "depositAmount must be > 0"); - feeAmount = getDepositFee(depositAmount, getTokenBalance(pool, tco2), getTotalSupply(pool)); + uint256 feeAmount = getDepositFee(depositAmount, getTokenBalance(pool, tco2), getTotalSupply(pool)); require(feeAmount <= depositAmount, "Fee must be lower or equal to deposit amount"); require(feeAmount > 0, "Fee must be greater than 0"); + feeDistribution = calculateFeeShares(feeAmount); } /// @notice Calculates the fee shares and recipients based on the total fee. /// @param totalFee The total fee to be distributed. - /// @return recipients The addresses of the fee recipients. - /// @return feesDenominatedInPoolTokens The amount of fees each recipient should receive. - function calculateFeeShares(uint256 totalFee) - internal - view - returns (address[] memory recipients, uint256[] memory feesDenominatedInPoolTokens) - { - feesDenominatedInPoolTokens = new uint256[](_recipients.length); + /// @return feeDistribution The recipients and the amount of fees each + /// recipient should receive. + function calculateFeeShares(uint256 totalFee) internal view returns (FeeDistribution memory feeDistribution) { + uint256[] memory shares = new uint256[](_recipients.length); uint256 restFee = totalFee; for (uint256 i = 0; i < _recipients.length; i++) { - feesDenominatedInPoolTokens[i] = (totalFee * _shares[i]) / 100; - restFee -= feesDenominatedInPoolTokens[i]; + shares[i] = (totalFee * _shares[i]) / 100; + restFee -= shares[i]; } - recipients = _recipients; - feesDenominatedInPoolTokens[0] += restFee; //we give rest of the fee (if any) to the first recipient + // If any fee is left, it is distributed to the first recipient. + // This may happen if any of the shares of the fee to be distributed + // has leftover from the division by 100 above. + shares[0] += restFee; + + feeDistribution.recipients = _recipients; + feeDistribution.shares = shares; } /// @notice Calculates the redemption fees for a given amount. /// @param tco2 The address of the TCO2 token. /// @param pool The address of the pool. /// @param redemptionAmount The amount to be redeemed. - /// @return feeAmount The fee to be charged in pool - /// tokens for this redemption. + /// @return feeDistribution How the fee is meant to be + /// distributed among the fee recipients. function calculateRedemptionFees(address tco2, address pool, uint256 redemptionAmount) external view override - returns (uint256 feeAmount) + returns (FeeDistribution memory feeDistribution) { require(redemptionAmount > 0, "redemptionAmount must be > 0"); - feeAmount = getRedemptionFee(redemptionAmount, getTokenBalance(pool, tco2), getTotalSupply(pool)); + uint256 feeAmount = getRedemptionFee(redemptionAmount, getTokenBalance(pool, tco2), getTotalSupply(pool)); require(feeAmount <= redemptionAmount, "Fee must be lower or equal to redemption amount"); require(feeAmount > 0, "Fee must be greater than 0"); - } - - /// @notice Calculates the fee shares and recipients for a deposit based on the total fee. - /// @param totalFee The total fee to be shared. - /// @return recipients The addresses of the fee recipients. - /// @return feesDenominatedInPoolTokens The amount of fees each recipient should receive. - function calculateDepositFeeShares(uint256 totalFee) - external - view - returns (address[] memory recipients, uint256[] memory feesDenominatedInPoolTokens) - { - return calculateFeeShares(totalFee); - } - - /// @notice Calculates the fee shares and recipients for a redemption based on the total fee. - /// @param totalFee The total fee to be shared. - /// @return recipients The addresses of the fee recipients. - /// @return feesDenominatedInPoolTokens The amount of fees each recipient should receive. - function calculateRedemptionFeeShares(uint256 totalFee) - external - view - returns (address[] memory recipients, uint256[] memory feesDenominatedInPoolTokens) - { - return calculateFeeShares(totalFee); + feeDistribution = calculateFeeShares(feeAmount); } /// @notice Gets the balance of the TCO2 token in a given pool. diff --git a/src/interfaces/IFeeCalculator.sol b/src/interfaces/IFeeCalculator.sol index f8515c3..9b2442d 100644 --- a/src/interfaces/IFeeCalculator.sol +++ b/src/interfaces/IFeeCalculator.sol @@ -5,6 +5,11 @@ // If you encounter a vulnerability or an issue, please contact pragma solidity ^0.8.13; +struct FeeDistribution { + address[] recipients; + uint256[] shares; +} + /// @title IFeeCalculator /// @author Neutral Labs Inc. /// @notice This interface defines methods for calculating fees. @@ -13,39 +18,21 @@ interface IFeeCalculator { /// @param tco2 The address of the TCO2 token. /// @param pool The address of the pool. /// @param depositAmount The amount to be deposited. - /// @return feeAmount The fee to be charged in pool - /// tokens for this deposit. + /// @return feeDistribution How the fee is meant to be + /// distributed among the fee recipients. function calculateDepositFees(address tco2, address pool, uint256 depositAmount) external view - returns (uint256 feeAmount); + returns (FeeDistribution memory feeDistribution); /// @notice Calculates the redemption fees for a given amount. /// @param tco2 The address of the TCO2 token. /// @param pool The address of the pool. /// @param redemptionAmount The amount to be redeemed. - /// @return feeAmount The fee to be charged in pool - /// tokens for this redemption. + /// @return feeDistribution How the fee is meant to be + /// distributed among the fee recipients. function calculateRedemptionFees(address tco2, address pool, uint256 redemptionAmount) external view - returns (uint256 feeAmount); - - /// @notice Calculates the fee shares and recipients for a deposit based on the total fee. - /// @param totalFee The total fee to be shared. - /// @return recipients The addresses of the fee recipients. - /// @return feesDenominatedInPoolTokens The amount of fees each recipient should receive. - function calculateDepositFeeShares(uint256 totalFee) - external - view - returns (address[] memory recipients, uint256[] memory feesDenominatedInPoolTokens); - - /// @notice Calculates the fee shares and recipients for a redemption based on the total fee. - /// @param totalFee The total fee to be shared. - /// @return recipients The addresses of the fee recipients. - /// @return feesDenominatedInPoolTokens The amount of fees each recipient should receive. - function calculateRedemptionFeeShares(uint256 totalFee) - external - view - returns (address[] memory recipients, uint256[] memory feesDenominatedInPoolTokens); + returns (FeeDistribution memory feeDistribution); } diff --git a/test/FeeCalculator.fuzzy.t.sol b/test/FeeCalculator.fuzzy.t.sol index ed2f43e..4f70cb2 100644 --- a/test/FeeCalculator.fuzzy.t.sol +++ b/test/FeeCalculator.fuzzy.t.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.13; import {Test, console2} from "forge-std/Test.sol"; import {FeeCalculator} from "../src/FeeCalculator.sol"; +import {FeeDistribution} from "../src/interfaces/IFeeCalculator.sol"; import {SD59x18, sd, intoUint256 as sdIntoUint256} from "@prb/math/src/SD59x18.sol"; import {UD60x18, ud, intoUint256} from "@prb/math/src/UD60x18.sol"; import "./TestUtilities.sol"; @@ -120,9 +121,9 @@ contract FeeCalculatorTestFuzzy is Test { // Act try feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), redemptionAmount) returns ( - uint256 feeAmount + FeeDistribution memory feeDistribution ) { - oneTimeFee = feeAmount; + oneTimeFee = feeDistribution.shares.sumOf(); } catch Error(string memory reason) { oneTimeRedemptionFailed = true; assertTrue( @@ -145,9 +146,9 @@ contract FeeCalculatorTestFuzzy is Test { for (uint256 i = 0; i < numberOfRedemptions; i++) { uint256 redemption = equalRedemption + (i == 0 ? restRedemption : 0); try feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), redemption) returns ( - uint256 feeAmount + FeeDistribution memory feeDistribution ) { - feeFromDividedRedemptions += feeAmount; + feeFromDividedRedemptions += feeDistribution.shares.sumOf(); total -= redemption; current -= redemption; mockPool.setTotalSupply(total); @@ -203,9 +204,9 @@ contract FeeCalculatorTestFuzzy is Test { // Act try feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount) returns ( - uint256 feeAmount + FeeDistribution memory feeDistribution ) { - oneTimeFee = feeAmount; + oneTimeFee = feeDistribution.shares.sumOf(); } catch Error(string memory reason) { oneTimeDepositFailed = true; assertTrue( @@ -223,9 +224,9 @@ contract FeeCalculatorTestFuzzy is Test { uint256 deposit = equalDeposit + (i == 0 ? restDeposit : 0); try feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), deposit) returns ( - uint256 feeAmount + FeeDistribution memory feeDistribution ) { - feeFromDividedDeposits += feeAmount; + feeFromDividedDeposits += feeDistribution.shares.sumOf(); total += deposit; current += deposit; mockPool.setTotalSupply(total); @@ -276,8 +277,10 @@ contract FeeCalculatorTestFuzzy is Test { mockToken.setTokenBalance(address(mockPool), 100 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory gotRecipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory gotRecipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(gotRecipients.length, recipients.length); diff --git a/test/FeeCalculator.t.sol b/test/FeeCalculator.t.sol index 05de176..823292a 100644 --- a/test/FeeCalculator.t.sol +++ b/test/FeeCalculator.t.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.13; import {Test, console2} from "forge-std/Test.sol"; import {FeeCalculator} from "../src/FeeCalculator.sol"; +import {FeeDistribution} from "../src/interfaces/IFeeCalculator.sol"; import {SD59x18, sd, intoUint256 as sdIntoUint256} from "@prb/math/src/SD59x18.sol"; import {UD60x18, ud, intoUint256} from "@prb/math/src/UD60x18.sol"; import "./TestUtilities.sol"; @@ -72,10 +73,13 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 500 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert + assertEq(feeDistribution.recipients.length, feeDistribution.shares.length, "array length mismatch"); assertEq(recipients[0], feeRecipient); assertEq(fees[0], 9718378209069523938); } @@ -90,11 +94,13 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 500 * 1e18); // Act - uint256 feeAmount = + FeeDistribution memory feeDistribution = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), redemptionAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert + assertEq(feeDistribution.recipients.length, feeDistribution.shares.length, "array length mismatch"); assertEq(recipients[0], feeRecipient); assertEq(fees[0], 2833521467902860250); } @@ -109,9 +115,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1 * 1e18); // Act - uint256 feeAmount = + FeeDistribution memory feeDistribution = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), redemptionAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -130,9 +137,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1e6 * 1e18); // Act - uint256 feeAmount = + FeeDistribution memory feeDistribution = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), redemptionAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -159,8 +167,10 @@ contract FeeCalculatorTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -190,8 +200,10 @@ contract FeeCalculatorTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -211,8 +223,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 15462 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -260,8 +274,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1e4 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -278,8 +294,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1e4 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -315,8 +333,10 @@ contract FeeCalculatorTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -361,8 +381,10 @@ contract FeeCalculatorTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -388,8 +410,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1e6 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -480,8 +504,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 0); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -498,8 +524,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 0); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -530,9 +558,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1000); // Act - uint256 feeAmount = + FeeDistribution memory feeDistribution = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), redemptionAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -549,8 +578,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 1000); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -567,8 +598,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 999); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -585,8 +618,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 0); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -604,8 +639,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), supply - 1); // Act - uint256 feeAmount = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -622,8 +659,10 @@ contract FeeCalculatorTest is Test { mockToken.setTokenBalance(address(mockPool), 55661911070827884041095553095); // Act - uint256 feeAmount = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -765,8 +804,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setDepositFeeScale(0.09 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), 100 * 1e18); - (, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), 100 * 1e18); + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(fees[0], 9718378209069523938 / 2); @@ -780,8 +820,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setDepositFeeRatioScale(0.2 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), 100 * 1e18); - (, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), 100 * 1e18); + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(fees[0], 1299819671838098442); @@ -795,8 +836,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setSingleAssetDepositRelativeFee(0.67 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), 100 * 1e18); - (, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), 100 * 1e18); + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(fees[0], 67 * 1e18); @@ -810,8 +852,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setRedemptionFeeScale(0.4 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), 100e18); - (, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), 100e18); + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(fees[0], 3778028623870480400); @@ -825,8 +868,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setRedemptionFeeShift(0.5 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), 100e18); - (, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), 100e18); + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(fees[0], 2303907724666580660); @@ -840,8 +884,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setSingleAssetRedemptionRelativeFee(0.83 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), 100 * 1e18); - (, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), 100 * 1e18); + uint256[] memory fees = feeDistribution.shares; assertEq(fees[0], 83 * 1e18); } @@ -857,8 +902,9 @@ contract FeeCalculatorTest is Test { feeCalculator.setDustAssetRedemptionRelativeFee(0.91 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), depositAmount); - (, uint256[] memory fees) = feeCalculator.calculateRedemptionFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateRedemptionFees(address(mockToken), address(mockPool), depositAmount); + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(fees[0], depositAmount * 91 / 100); diff --git a/test/FeeCalculatorLaunchParams.fuzzy.t.sol b/test/FeeCalculatorLaunchParams.fuzzy.t.sol index 89c893a..3e91a7a 100644 --- a/test/FeeCalculatorLaunchParams.fuzzy.t.sol +++ b/test/FeeCalculatorLaunchParams.fuzzy.t.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.13; import {Test, console2} from "forge-std/Test.sol"; import {FeeCalculator} from "../src/FeeCalculator.sol"; +import {FeeDistribution} from "../src/interfaces/IFeeCalculator.sol"; import "./TestUtilities.sol"; contract FeeCalculatorLaunchParamsTestFuzzy is Test { @@ -116,9 +117,9 @@ contract FeeCalculatorLaunchParamsTestFuzzy is Test { // Act try feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount) returns ( - uint256 feeAmount + FeeDistribution memory feeDistribution ) { - oneTimeFee = feeAmount; + oneTimeFee = feeDistribution.shares.sumOf(); } catch Error(string memory reason) { oneTimeDepositFailed = true; assertTrue( @@ -137,9 +138,9 @@ contract FeeCalculatorLaunchParamsTestFuzzy is Test { uint256 deposit = equalDeposit + (i == 0 ? restDeposit : 0); try feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), deposit) returns ( - uint256 feeAmount + FeeDistribution memory feeDistribution ) { - feeFromDividedDeposits += feeAmount; + feeFromDividedDeposits += feeDistribution.shares.sumOf(); total += deposit; current += deposit; mockPool.setTotalSupply(total); diff --git a/test/FeeCalculatorLaunchParams.t.sol b/test/FeeCalculatorLaunchParams.t.sol index d31ee20..b9c42b2 100644 --- a/test/FeeCalculatorLaunchParams.t.sol +++ b/test/FeeCalculatorLaunchParams.t.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.13; import {Test, console2} from "forge-std/Test.sol"; import {FeeCalculator} from "../src/FeeCalculator.sol"; +import {FeeDistribution} from "../src/interfaces/IFeeCalculator.sol"; import "./TestUtilities.sol"; contract FeeCalculatorLaunchParamsTest is Test { @@ -41,8 +42,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 500 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -70,8 +73,10 @@ contract FeeCalculatorLaunchParamsTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -101,8 +106,10 @@ contract FeeCalculatorLaunchParamsTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -122,8 +129,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 15462 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -172,8 +181,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 1e4 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -191,8 +202,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 1e4 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -229,8 +242,10 @@ contract FeeCalculatorLaunchParamsTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -276,8 +291,10 @@ contract FeeCalculatorLaunchParamsTest is Test { feeCalculator.feeSetup(_recipients, _feeShares); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient1); @@ -304,8 +321,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 1e6 * 1e18); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -353,8 +372,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 0); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -385,8 +406,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 1000); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient); @@ -417,8 +440,10 @@ contract FeeCalculatorLaunchParamsTest is Test { mockToken.setTokenBalance(address(mockPool), 0); // Act - uint256 feeAmount = feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); - (address[] memory recipients, uint256[] memory fees) = feeCalculator.calculateDepositFeeShares(feeAmount); + FeeDistribution memory feeDistribution = + feeCalculator.calculateDepositFees(address(mockToken), address(mockPool), depositAmount); + address[] memory recipients = feeDistribution.recipients; + uint256[] memory fees = feeDistribution.shares; // Assert assertEq(recipients[0], feeRecipient);