Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LILA-6145] Consolidate interface functions #36

Merged
merged 1 commit into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 24 additions & 45 deletions src/FeeCalculator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
0xmichalis marked this conversation as resolved.
Show resolved Hide resolved
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.
Expand Down
35 changes: 11 additions & 24 deletions src/interfaces/IFeeCalculator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
// If you encounter a vulnerability or an issue, please contact <[email protected]>
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.
Expand All @@ -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);
}
23 changes: 13 additions & 10 deletions test/FeeCalculator.fuzzy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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(
Expand All @@ -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);
Expand Down Expand Up @@ -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(
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading