Skip to content

Commit

Permalink
feat: add getFeePercentage(exhangeToken,price) function
Browse files Browse the repository at this point in the history
  • Loading branch information
0xlucian committed Oct 7, 2024
1 parent ac14d32 commit d9e78dc
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 9 deletions.
4 changes: 4 additions & 0 deletions contracts/domain/BosonErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -376,4 +376,8 @@ interface BosonErrors {
error FeeAmountTooHigh();
// Price does not cover the cancellation penalty
error PriceDoesNotCoverPenalty();

//Fee Table related
// Exchange token should be different than $BOSON when requesting feePercentage
error InvalidExchangeToken();
}
19 changes: 18 additions & 1 deletion contracts/interfaces/handlers/IBosonConfigHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { IBosonConfigEvents } from "../events/IBosonConfigEvents.sol";
*
* @notice Handles management of configuration within the protocol.
*
* The ERC-165 identifier for this interface is: 0xc040bf51
* The ERC-165 identifier for this interface is: 0x13fd085d
*/
interface IBosonConfigHandler is IBosonConfigEvents, BosonErrors {
/**
Expand Down Expand Up @@ -156,6 +156,23 @@ interface IBosonConfigHandler is IBosonConfigEvents, BosonErrors {
*/
function getProtocolFeePercentage() external view returns (uint256);

/**
* @notice Gets the protocol fee percentage based on protocol fee table
*
* @dev This function calculates the protocol fee percentage for specific token and price.
* If the token has a custom fee table configured, it returns the corresponding fee percentage
* for the price range. If the token does not have a custom fee table, it falls back
* to the default protocol fee percentage.
*
* Reverts if the exchange token is BOSON.
*
* @param _exchangeToken - The address of the token being used for the exchange.
* @param _price - The price of the item or service in the exchange.
*
* @return the protocol fee percentage for given price and exchange token
*/
function getProtocolFeePercentage(address _exchangeToken, uint256 _price) external view returns (uint256);

/**
* @notice Retrieves the protocol fee percentage for a given exchange token and price.
*
Expand Down
29 changes: 21 additions & 8 deletions contracts/protocol/bases/ProtocolBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -695,31 +695,44 @@ abstract contract ProtocolBase is PausableBase, ReentrancyGuardBase, BosonErrors
* @return protocolFee - the protocol fee
*/
function _getProtocolFee(address _exchangeToken, uint256 _price) internal view returns (uint256 protocolFee) {
ProtocolLib.ProtocolFees storage fees = protocolFees();
// Check if the exchange token is the Boson token
if (_exchangeToken == protocolAddresses().token) {
// Apply the flatBoson fee if the exchange token is the Boson token
return fees.flatBoson;
// Return the flatBoson fee percentage if the exchange token is the Boson token
return protocolFees().flatBoson;
}
uint256 feePercentage = _getFeePercentage(_exchangeToken, _price);
return FundsLib.applyPercent(_price, feePercentage);
}

/**
* @notice calculate the protocol fee percentage for a given exchange
*
* @param _exchangeToken - the token used for the exchange
* @param _price - the price of the exchange
* @return feePercentage - the protocol fee percentage based on token price (using protocol fee table)
*/
function _getFeePercentage(address _exchangeToken, uint256 _price) internal view returns (uint256 feePercentage) {
if (_exchangeToken == protocolAddresses().token) revert InvalidExchangeToken();

ProtocolLib.ProtocolFees storage fees = protocolFees();
uint256[] storage priceRanges = fees.tokenPriceRanges[_exchangeToken];
uint256[] storage feePercentages = fees.tokenFeePercentages[_exchangeToken];

// If the token has a custom fee table, calculate based on the price ranges
// If the token has a custom fee table, find the appropriate percentage
uint256 priceRangesLength = priceRanges.length;
if (priceRangesLength > 0) {
for (uint256 i; i < priceRangesLength; ++i) {
if (_price <= priceRanges[i]) {
// Apply the fee percentage for the matching price range
return FundsLib.applyPercent(_price, feePercentages[i]);
// Return the fee percentage for the matching price range
return feePercentages[i];
}
}
// If price exceeds all ranges, use the highest fee percentage
return FundsLib.applyPercent(_price, feePercentages[priceRangesLength - 1]);
return feePercentages[priceRangesLength - 1];
}

// If no custom fee table exists, fallback to using the default protocol percentage
return FundsLib.applyPercent(_price, fees.percentage);
return fees.percentage;
}

/**
Expand Down
19 changes: 19 additions & 0 deletions contracts/protocol/facets/ConfigHandlerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@ contract ConfigHandlerFacet is IBosonConfigHandler, ProtocolBase {
return protocolFees().percentage;
}

/**
* @notice Gets the protocol fee percentage based on protocol fee table
*
* @dev This function calculates the protocol fee percentage for specific token and price.
* If the token has a custom fee table configured, it returns the corresponding fee percentage
* for the price range. If the token does not have a custom fee table, it falls back
* to the default protocol fee percentage.
*
* Reverts if the exchange token is BOSON.
*
* @param _exchangeToken - The address of the token being used for the exchange.
* @param _price - The price of the item or service in the exchange.
*
* @return the protocol fee percentage for given price and exchange token
*/
function getProtocolFeePercentage(address _exchangeToken, uint256 _price) external view override returns (uint256) {
return _getFeePercentage(_exchangeToken, _price);
}

/**
* @notice Retrieves the protocol fee percentage for a given token and price.
*
Expand Down
3 changes: 3 additions & 0 deletions scripts/config/revert-reasons.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,7 @@ exports.RevertReasons = {
TOKEN_ID_MANDATORY: "TokenIdMandatory",
NEGATIVE_PRICE_NOT_ALLOWED: "NegativePriceNotAllowed",
PRICE_DOES_NOT_COVER_PENALTY: "PriceDoesNotCoverPenalty",

//Fee Table related
INVALID_EXCHANGE_TOKEN: "InvalidExchangeToken",
};
8 changes: 8 additions & 0 deletions test/protocol/ConfigHandlerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -989,13 +989,15 @@ describe("IBosonConfigHandler", function () {
feeTier = feePercentages[i];
expectedFeeAmount = applyPercentage(exchangeAmount, feeTier);
expect(await configHandler.getProtocolFee(usdcAddress, exchangeAmount)).to.equal(expectedFeeAmount);
expect(await configHandler.getProtocolFeePercentage(usdcAddress, exchangeAmount)).to.equal(feeTier);
}

// check for a way bigger value
feeTier = feePercentages[feePercentages.length - 1];
exchangeAmount = BigInt(feePriceRanges[feePriceRanges.length - 1]) * BigInt(2);
expectedFeeAmount = applyPercentage(exchangeAmount, feeTier);
expect(await configHandler.getProtocolFee(usdcAddress, exchangeAmount)).to.equal(expectedFeeAmount);
expect(await configHandler.getProtocolFeePercentage(usdcAddress, exchangeAmount)).to.equal(feeTier);
});

it("should update state and return boson flat fee if boson token used as exchange token", async function () {
Expand Down Expand Up @@ -1036,6 +1038,12 @@ describe("IBosonConfigHandler", function () {
configHandler.connect(deployer).setProtocolFeeTable(usdcAddress, newPriceRanges, feePercentages)
).to.revertedWithCustomError(bosonErrors, RevertReasons.NON_ASCENDING_ORDER);
});
it("getProtocolFeePercentage should not accept BOSON token as parameter", async function () {
const randomPrice = 10000;
await expect(
configHandler.connect(rando).getProtocolFeePercentage(await token.getAddress(), randomPrice)
).to.revertedWithCustomError(bosonErrors, RevertReasons.INVALID_EXCHANGE_TOKEN);
});
});
});
});
Expand Down

0 comments on commit d9e78dc

Please sign in to comment.