Skip to content

Commit

Permalink
refactor: address PR comments and optimise code
Browse files Browse the repository at this point in the history
  • Loading branch information
0xlucian committed Oct 2, 2024
1 parent b374ad5 commit 2fa00fe
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 46 deletions.
2 changes: 2 additions & 0 deletions contracts/domain/BosonErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ interface BosonErrors {
error InvalidState();
// Two or more array parameters with different lengths
error ArrayLengthMismatch();
// Array elements that are not in ascending order (i.e arr[i-1] > arr[i])
error NonAscendingOrder();

// Reentrancy guard
// Reentrancy guard is active and second call to protocol is made
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/events/IBosonConfigEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ interface IBosonConfigEvents {
event MinDisputePeriodChanged(uint256 minDisputePeriod, address indexed executedBy);
event MaxPremintedVouchersChanged(uint256 maxPremintedVouchers, address indexed executedBy);
event AccessControllerAddressChanged(address indexed accessControllerAddress, address indexed executedBy);
event FeeTableUpdated(address indexed token, uint256[] priceRanges, uint256[] feePercentages);
event FeeTableUpdated(address indexed token, uint256[] priceRanges, uint256[] feePercentages, address indexed executedBy);
}
2 changes: 1 addition & 1 deletion contracts/interfaces/handlers/IBosonConfigHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ interface IBosonConfigHandler is IBosonConfigEvents, BosonErrors {
*
* @return The protocol fee amount based on the token and the price.
*/
function getProtocolFeePercentage(address _exchangeToken, uint256 _price) external view returns (uint256);
function getProtocolFee(address _exchangeToken, uint256 _price) external view returns (uint256);

/**
* @notice Sets the flat protocol fee for exchanges in $BOSON.
Expand Down
2 changes: 1 addition & 1 deletion contracts/protocol/bases/OfferBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ contract OfferBase is ProtocolBase, IBosonOfferEvents {
if (_offer.buyerCancelPenalty > offerPrice) revert InvalidOfferPenalty();
if (_offer.priceType == PriceType.Static) {
// Calculate and set the protocol fee
uint256 protocolFee = getProtocolFee(_offer.exchangeToken, offerPrice);
uint256 protocolFee = _getProtocolFee(_offer.exchangeToken, offerPrice);

// Calculate the agent fee amount
uint256 agentFeeAmount = (agent.feePercentage * offerPrice) / HUNDRED_PERCENT;
Expand Down
25 changes: 14 additions & 11 deletions contracts/protocol/bases/ProtocolBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { EIP712Lib } from "../libs/EIP712Lib.sol";
import { BosonTypes } from "../../domain/BosonTypes.sol";
import { PausableBase } from "./PausableBase.sol";
import { ReentrancyGuardBase } from "./ReentrancyGuardBase.sol";
import { FundsLib } from "../libs/FundsLib.sol";

/**
* @title ProtocolBase
Expand Down Expand Up @@ -693,32 +694,34 @@ abstract contract ProtocolBase is PausableBase, ReentrancyGuardBase, BosonErrors
* @param _price - the price of the exchange
* @return protocolFee - the protocol fee
*/
function getProtocolFee(address _exchangeToken, uint256 _price) internal view returns (uint256 protocolFee) {
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 protocolFees().flatBoson;
return fees.flatBoson;
}

uint256[] storage priceRanges = protocolFees().tokenPriceRanges[_exchangeToken];
uint256[] storage feePercentages = protocolFees().tokenFeePercentages[_exchangeToken];
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 (priceRanges.length > 0 && feePercentages.length > 0) {
for (uint256 i = 0; i < priceRanges.length; i++) {
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
uint256 feePercentage = feePercentages[i];
return (feePercentage * _price) / HUNDRED_PERCENT;
return FundsLib.applyPercent(_price,feePercentages[i]);

}
}
// If price exceeds all ranges, use the highest fee percentage
uint256 highestFeePercentage = feePercentages[priceRanges.length - 1];
return (highestFeePercentage * _price) / HUNDRED_PERCENT;
return FundsLib.applyPercent(_price,feePercentages[priceRangesLength - 1]);
}

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

}

/**
Expand Down
17 changes: 8 additions & 9 deletions contracts/protocol/facets/ConfigHandlerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ contract ConfigHandlerFacet is IBosonConfigHandler, ProtocolBase {
uint256[] calldata _priceRanges,
uint256[] calldata _feePercentages
) external override onlyRole(ADMIN) nonReentrant {
checkNonZeroAddress(_tokenAddress);
if (_priceRanges.length != _feePercentages.length) revert ArrayLengthMismatch();
// Clear existing price ranges and percentage tiers
delete protocolFees().tokenPriceRanges[_tokenAddress];
Expand All @@ -257,7 +256,7 @@ contract ConfigHandlerFacet is IBosonConfigHandler, ProtocolBase {
setTokenPriceRanges(_tokenAddress, _priceRanges);
setTokenFeePercentages(_tokenAddress, _feePercentages);
}
emit FeeTableUpdated(_tokenAddress, _priceRanges, _feePercentages);
emit FeeTableUpdated(_tokenAddress, _priceRanges, _feePercentages, msgSender());
}

/**
Expand All @@ -283,8 +282,8 @@ contract ConfigHandlerFacet is IBosonConfigHandler, ProtocolBase {
*
* @return The protocol fee amount based on the token and the price.
*/
function getProtocolFeePercentage(address _exchangeToken, uint256 _price) external view override returns (uint256) {
return getProtocolFee(_exchangeToken, _price);
function getProtocolFee(address _exchangeToken, uint256 _price) external view override returns (uint256) {
return _getProtocolFee(_exchangeToken, _price);
}

/**
Expand Down Expand Up @@ -618,10 +617,10 @@ contract ConfigHandlerFacet is IBosonConfigHandler, ProtocolBase {
* @param _priceRanges - array of price ranges for the token
*/
function setTokenPriceRanges(address _tokenAddress, uint256[] calldata _priceRanges) internal {
// Set new price ranges
for (uint256 i = 0; i < _priceRanges.length; i++) {
protocolFees().tokenPriceRanges[_tokenAddress].push(_priceRanges[i]);
for (uint256 i = 1; i < _priceRanges.length; ++i) {
if(_priceRanges[i] < _priceRanges[i - 1]) revert NonAscendingOrder();
}
protocolFees().tokenPriceRanges[_tokenAddress] = _priceRanges;
}

/**
Expand All @@ -632,10 +631,10 @@ contract ConfigHandlerFacet is IBosonConfigHandler, ProtocolBase {
*/
function setTokenFeePercentages(address _tokenAddress, uint256[] calldata _feePercentages) internal {
// Set the fee percentages for the token
for (uint256 i = 0; i < _feePercentages.length; i++) {
for (uint256 i; i < _feePercentages.length; ++i) {
checkMaxPercententage(_feePercentages[i]);
protocolFees().tokenFeePercentages[_tokenAddress].push(_feePercentages[i]);
}
protocolFees().tokenFeePercentages[_tokenAddress] = _feePercentages;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion contracts/protocol/facets/PriceDiscoveryHandlerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ contract PriceDiscoveryHandlerFacet is IBosonPriceDiscoveryHandler, PriceDiscove

// Calculate fees
address exchangeToken = offer.exchangeToken;
uint256 protocolFeeAmount = getProtocolFee(exchangeToken, actualPrice);
uint256 protocolFeeAmount = _getProtocolFee(exchangeToken, actualPrice);

{
// Calculate royalties
Expand Down
2 changes: 1 addition & 1 deletion contracts/protocol/facets/SequentialCommitHandlerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ contract SequentialCommitHandlerFacet is IBosonSequentialCommitHandler, PriceDis

{
// Calculate fees
thisExchangeCost.protocolFeeAmount = getProtocolFee(exchangeToken, thisExchangeCost.price);
thisExchangeCost.protocolFeeAmount = _getProtocolFee(exchangeToken, thisExchangeCost.price);

// Calculate royalties
{
Expand Down
1 change: 1 addition & 0 deletions scripts/config/revert-reasons.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ exports.RevertReasons = {
INVALID_STATE: "InvalidState",
ARRAY_LENGTH_MISMATCH: "ArrayLengthMismatch",
REENTRANCY_GUARD: "ReentrancyGuard",
NON_ASCENDING_ORDER: "NonAscendingOrder",

// Facet initializer related
ALREADY_INITIALIZED: "AlreadyInitialized",
Expand Down
8 changes: 3 additions & 5 deletions test/example/SnapshotGateTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,9 @@ describe("SnapshotGate", function () {
maxPremintedVouchers: 10000,
},
// Protocol fees
{
percentage: protocolFeePercentage,
flatBoson: protocolFeeFlatBoson,
buyerEscalationDepositPercentage,
},
protocolFeePercentage,
protocolFeeFlatBoson,
buyerEscalationDepositPercentage,
];

const facetNames = [
Expand Down
31 changes: 15 additions & 16 deletions test/protocol/ConfigHandlerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ describe("IBosonConfigHandler", function () {
// Set new protocol fee precentage address, testing for the event
await expect(configHandler.connect(deployer).setProtocolFeeTable(usdcAddress, feePriceRanges, feePercentages))
.to.emit(configHandler, "FeeTableUpdated")
.withArgs(usdcAddress, feePriceRanges, feePercentages);
.withArgs(usdcAddress, feePriceRanges, feePercentages, await deployer.getAddress());
});

it("should update state and return fee amount based on configured fee table", async function () {
Expand All @@ -988,26 +988,20 @@ describe("IBosonConfigHandler", function () {
exchangeAmount = feePriceRanges[i];
feeTier = feePercentages[i];
expectedFeeAmount = applyPercentage(exchangeAmount, feeTier);
expect(await configHandler.getProtocolFeePercentage(usdcAddress, exchangeAmount)).to.equal(
expectedFeeAmount
);
expect(await configHandler.getProtocolFee(usdcAddress, exchangeAmount)).to.equal(expectedFeeAmount);
}

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

it("should update state and return boson flat fee if boson token used as exchange token", async function () {
await configHandler.connect(deployer).setProtocolFeeTable(usdcAddress, feePriceRanges, feePercentages);
exchangeAmount = feePriceRanges[0];
expect(await configHandler.getProtocolFeePercentage(bosonToken, exchangeAmount)).to.equal(
protocolFeeFlatBoson
);
expect(await configHandler.getProtocolFee(bosonToken, exchangeAmount)).to.equal(protocolFeeFlatBoson);
});

context("💔 Revert Reasons", async function () {
Expand All @@ -1017,12 +1011,6 @@ describe("IBosonConfigHandler", function () {
configHandler.connect(rando).setProtocolFeeTable(usdcAddress, feePriceRanges, feePercentages)
).to.revertedWithCustomError(bosonErrors, RevertReasons.ACCESS_DENIED);
});

it("exchange token is zero address", async function () {
await expect(
configHandler.connect(deployer).setProtocolFeeTable(ZeroAddress, feePriceRanges, feePercentages)
).to.revertedWithCustomError(bosonErrors, RevertReasons.INVALID_ADDRESS);
});
it("price ranges count different from fee percents", async function () {
const newPriceRanges = [...feePriceRanges, parseUnits("10", "ether").toString()];
await expect(
Expand All @@ -1037,6 +1025,17 @@ describe("IBosonConfigHandler", function () {
configHandler.connect(deployer).setProtocolFeeTable(usdcAddress, feePriceRanges, newFeePercentages)
).to.revertedWithCustomError(bosonErrors, RevertReasons.FEE_PERCENTAGE_INVALID);
});
it("price ranges are not in ascending order", async function () {
const newPriceRanges = [
parseUnits("1", "ether").toString(),
parseUnits("3", "ether").toString(),
parseUnits("2", "ether").toString(),
];

await expect(
configHandler.connect(deployer).setProtocolFeeTable(usdcAddress, newPriceRanges, feePercentages)
).to.revertedWithCustomError(bosonErrors, RevertReasons.NON_ASCENDING_ORDER);
});
});
});
});
Expand Down

0 comments on commit 2fa00fe

Please sign in to comment.