// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import "../../listing/listing-strategies/ListingStrategies.sol"; import "../../tax/tax-strategies/TaxStrategies.sol"; import "../../renting/Rentings.sol"; library ERC20RewardDistributionHelper { struct RentalExternalERC20RewardFees { address token; uint256 totalReward; uint256 listerRewardFee; uint256 renterRewardFee; uint256 universeRewardFee; uint256 protocolRewardFee; } /** * A constant that represents one hundred percent for calculation. * This defines a calculation precision for percentage values as two decimals. * For example: 1 is 0.01%, 100 is 1%, 10_000 is 100%. */ uint16 private constant _HUNDRED_PERCENT = 10_000; function getRentalExternalERC20RewardFees( Rentings.Agreement memory agreement, address token, uint256 rewardAmount ) internal view returns (RentalExternalERC20RewardFees memory rentalExternalERC20RewardFees) { // Listing Terms will have equivalent (in terms of strategy type) Tax Terms. IListingTermsRegistry.ListingTerms memory listingTerms = agreement.agreementTerms.listingTerms; if (listingTerms.strategyId == ListingStrategies.FIXED_RATE_WITH_REWARD) { ( uint16 listerRewardPercentage, uint16 universeRewardTaxPercentage, uint16 protocolRewardTaxPercentage ) = retrieveRewardPercentages(agreement); rentalExternalERC20RewardFees = calculateExternalRewardBasedFees( token, rewardAmount, listerRewardPercentage, universeRewardTaxPercentage, protocolRewardTaxPercentage ); } else if (listingTerms.strategyId == ListingStrategies.FIXED_RATE) { rentalExternalERC20RewardFees = calculateExternalRewardForFixedRate(token, rewardAmount); } } function retrieveRewardPercentages(Rentings.Agreement memory agreement) internal view returns ( uint16 listerRewardPercentage, uint16 universeRewardTaxPercentage, uint16 protocolRewardTaxPercentage ) { IListingTermsRegistry.ListingTerms memory listingTerms = agreement.agreementTerms.listingTerms; ITaxTermsRegistry.TaxTerms memory universeTaxTerms = agreement.agreementTerms.universeTaxTerms; ITaxTermsRegistry.TaxTerms memory protocolTaxTerms = agreement.agreementTerms.protocolTaxTerms; (, listerRewardPercentage) = ListingStrategies.decodeFixedRateWithRewardListingStrategyParams(listingTerms); (, universeRewardTaxPercentage) = TaxStrategies.decodeFixedRateWithRewardTaxStrategyParams(universeTaxTerms); (, protocolRewardTaxPercentage) = TaxStrategies.decodeFixedRateWithRewardTaxStrategyParams(protocolTaxTerms); } function calculateExternalRewardBasedFees( address token, uint256 rewardAmount, uint16 listerRewardPercentage, uint16 universeRewardTaxPercentage, uint16 protocolRewardTaxPercentage ) internal pure returns (RentalExternalERC20RewardFees memory externalRewardFees) { externalRewardFees.token = token; externalRewardFees.totalReward = rewardAmount; uint256 leftoverRewardAmount = rewardAmount; externalRewardFees.universeRewardFee = (leftoverRewardAmount * universeRewardTaxPercentage) / _HUNDRED_PERCENT; if (leftoverRewardAmount <= externalRewardFees.universeRewardFee) { externalRewardFees.universeRewardFee = leftoverRewardAmount; return externalRewardFees; } leftoverRewardAmount -= externalRewardFees.universeRewardFee; externalRewardFees.protocolRewardFee = (leftoverRewardAmount * protocolRewardTaxPercentage) / _HUNDRED_PERCENT; if (leftoverRewardAmount <= externalRewardFees.protocolRewardFee) { externalRewardFees.protocolRewardFee = leftoverRewardAmount; return externalRewardFees; } leftoverRewardAmount -= externalRewardFees.protocolRewardFee; externalRewardFees.listerRewardFee = (leftoverRewardAmount * listerRewardPercentage) / _HUNDRED_PERCENT; if (leftoverRewardAmount <= externalRewardFees.listerRewardFee) { externalRewardFees.listerRewardFee = leftoverRewardAmount; return externalRewardFees; } externalRewardFees.renterRewardFee = leftoverRewardAmount - externalRewardFees.listerRewardFee; } function calculateExternalRewardForFixedRate(address token, uint256 rewardAmount) internal pure returns (RentalExternalERC20RewardFees memory externalRewardFees) { externalRewardFees.token = token; externalRewardFees.totalReward = rewardAmount; externalRewardFees.renterRewardFee = rewardAmount; } }