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

ProtocolFeeSplitter factory default #2133

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0d785e1
feat: add clearRevenueSharingFeePercentage, to revert to default reve…
EndymionJkb Dec 10, 2022
5075320
test: add tests for new feature; refactor generally
EndymionJkb Dec 10, 2022
1d31839
feat: add PoolRevenueShareCleared event
EndymionJkb Dec 10, 2022
7de3061
feat: add factory-specific default revenue share overrides
EndymionJkb Dec 10, 2022
250493b
feat: add getter for factory override
EndymionJkb Dec 10, 2022
5683f06
feat: add tests for factory overrides
EndymionJkb Dec 10, 2022
26e718a
refactor: remove double event
EndymionJkb Dec 10, 2022
d2a1273
Merge branch 'splitter-sentinel' into splitter-factory-default
EndymionJkb Dec 10, 2022
acfdfb0
lint
EndymionJkb Dec 10, 2022
0ac6a66
Merge branch 'splitter-sentinel' into splitter-factory-default
EndymionJkb Dec 10, 2022
6216495
lint
EndymionJkb Dec 10, 2022
722bcc2
Merge branch 'master' into splitter-factory-default
EndymionJkb Dec 13, 2022
64e4bfd
fix: merge conflict on comment
EndymionJkb Dec 13, 2022
c8845d2
fix: remove duplicated comment
EndymionJkb Dec 13, 2022
76e3585
Merge branch 'master' into splitter-factory-default
EndymionJkb Dec 13, 2022
646cc3d
Merge branch 'master' into splitter-beneficiary
EndymionJkb Dec 13, 2022
e272489
fix: merge conflict
EndymionJkb Dec 13, 2022
20a8da6
Merge branch 'master' into splitter-factory-default
EndymionJkb Jan 2, 2023
bfd9882
Merge branch 'master' into splitter-factory-default
EndymionJkb Jan 4, 2023
ee8bfd6
Merge branch 'master' into splitter-factory-default
EndymionJkb Jan 4, 2023
8ff3aa2
Merge branch 'master' into splitter-factory-default
EndymionJkb Jan 6, 2023
e95ce3d
Merge branch 'master' into splitter-factory-default
EndymionJkb Feb 15, 2023
1b72dfd
Merge branch 'master' into splitter-factory-default
EndymionJkb Feb 24, 2023
13e11fe
Merge branch 'master' into splitter-factory-default
EndymionJkb Mar 6, 2023
0b910d9
Merge branch 'master' into splitter-factory-default
EndymionJkb Mar 12, 2023
f07c49b
fix: adjust global permission signature
EndymionJkb Mar 12, 2023
53891fe
Merge branch 'master' into splitter-factory-default
EndymionJkb Mar 22, 2023
dd1568e
fix: adjust test for create2
EndymionJkb Mar 22, 2023
b5da1b9
Merge branch 'master' into splitter-factory-default
EndymionJkb Apr 15, 2023
a7498b7
Merge branch 'master' into splitter-factory-default
EndymionJkb Apr 25, 2023
b9b526f
Merge branch 'master' into splitter-factory-default
EndymionJkb Jun 9, 2023
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
28 changes: 24 additions & 4 deletions pkg/interfaces/contracts/standalone-utils/IProtocolFeeSplitter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ interface IProtocolFeeSplitter {
event PoolRevenueShareCleared(bytes32 indexed poolId);
event PoolBeneficiaryChanged(bytes32 indexed poolId, address newBeneficiary);
event DefaultRevenueSharePercentageChanged(uint256 revenueSharePercentage);
event FactoryDefaultRevenueSharePercentageChanged(address indexed factory, uint256 revenueSharePercentage);
event FactoryDefaultRevenueSharePercentageCleared(address indexed factory);
event DAOFundsRecipientChanged(address newDaoFundsRecipient);

// Fund recipients
Expand Down Expand Up @@ -95,10 +97,28 @@ interface IProtocolFeeSplitter {
function setDefaultRevenueSharePercentage(uint256 defaultRevenueSharePercentage) external;

/**
* @notice Allows an authorized user to change the revenueShare for a given pool.
* @dev This is a permissioned function.
* @param poolId - the poolId of the pool where the revenue share will change.
* @param revenueSharePercentage - the new revenue share percentage.
* @notice Returns the revenue share associated with the given factory
* @dev Reverts if no revenue share was set for this factory
* @param factory - the address of the factory with a default revenue share percentage
*/
function getFactoryDefaultRevenueSharePercentage(address factory) external view returns (uint256);

/**
* @notice Allows a authorized user to change the default revenue sharing fee percentage for a given factory
* @param factory - address of the factory
* @param feePercentage - new default revenue sharing fee percentage
*/
function setFactoryDefaultRevenueSharePercentage(address factory, uint256 feePercentage) external;

/**
* @notice Allows a authorized user to remove a default revenue sharing fee override for a given factory
* @param factory - address of the factory
*/
function clearFactoryDefaultRevenueSharePercentage(address factory) external;

/**
* @notice Ignore any previously set revenue sharing percentage, and begin using the default.
* @param poolId - the poolId of the pool to begin using the default revenue share percentage.
*/
function setRevenueSharePercentage(bytes32 poolId, uint256 revenueSharePercentage) external;

Expand Down
59 changes: 57 additions & 2 deletions pkg/standalone-utils/contracts/ProtocolFeeSplitter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@ pragma solidity >=0.7.0 <0.9.0;
import "@balancer-labs/v2-interfaces/contracts/standalone-utils/IProtocolFeeSplitter.sol";
import "@balancer-labs/v2-interfaces/contracts/standalone-utils/IProtocolFeesWithdrawer.sol";
import "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";

import "@balancer-labs/v2-solidity-utils/contracts/helpers/SingletonAuthentication.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/EnumerableMap.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol";
import "@balancer-labs/v2-interfaces/contracts/vault/IProtocolFeesCollector.sol";

interface Pool {
function getOwner() external view returns (address);
}

interface Factory {
function isPoolFromFactory(address pool) external view returns (bool);
}

/**
* @notice Support revenue sharing for individual pools between the DAO and designated recipients.
* @dev This contract is responsible for splitting the BPT profits collected by the ProtocolFeeCollector between
Expand All @@ -36,8 +41,11 @@ interface Pool {
* token were on this denyList.
*/
contract ProtocolFeeSplitter is IProtocolFeeSplitter, SingletonAuthentication {
using EnumerableMap for EnumerableMap.IERC20ToUint256Map;
using FixedPoint for uint256;

string private constant _UNDEFINED_FACTORY_SHARE = "Share undefined for this factory";

// All fee percentages are 18-decimal fixed point numbers.
// Absolute maximum fee percentage (1e18 = 100%).
uint256 private constant _MAX_REVENUE_SHARE_PERCENTAGE = 50e16; // 50%
Expand All @@ -50,6 +58,11 @@ contract ProtocolFeeSplitter is IProtocolFeeSplitter, SingletonAuthentication {
// The default revenue share given to pools; can be updated by governance (1e18 = 100%, 1e16 = 1%).
uint256 private _defaultRevenueSharePercentage;

// Allow the default revenue sharing fee percentage to be overridden for individual factories.
EnumerableMap.IERC20ToUint256Map private _revenueShareFactoryOverrides;

// By default, the `overrideSet` flag is false, and all Pools use the default revenue share percentage.

// Packed to use 1 storage slot
// 1e18 (100% - maximum fee value) can fit in uint88
struct RevenueShareSettings {
Expand All @@ -75,6 +88,23 @@ contract ProtocolFeeSplitter is IProtocolFeeSplitter, SingletonAuthentication {
return _daoFundsRecipient;
}

function setFactoryDefaultRevenueSharePercentage(address factory, uint256 feePercentage)
external
override
authenticate
{
_require(feePercentage <= _MAX_REVENUE_SHARE_PERCENTAGE, Errors.SPLITTER_FEE_PERCENTAGE_TOO_HIGH);
_revenueShareFactoryOverrides.set(IERC20(factory), feePercentage);

emit FactoryDefaultRevenueSharePercentageChanged(factory, feePercentage);
}

function clearFactoryDefaultRevenueSharePercentage(address factory) external override authenticate {
require(_revenueShareFactoryOverrides.remove(IERC20(factory)), _UNDEFINED_FACTORY_SHARE);

emit FactoryDefaultRevenueSharePercentageCleared(factory);
}

/// @inheritdoc IProtocolFeeSplitter
function setDaoFundsRecipient(address newDaoFundsRecipient) external override authenticate {
_daoFundsRecipient = newDaoFundsRecipient;
Expand Down Expand Up @@ -182,6 +212,13 @@ contract ProtocolFeeSplitter is IProtocolFeeSplitter, SingletonAuthentication {

// Internal functions

function getFactoryDefaultRevenueSharePercentage(address factory) external view override returns (uint256) {
require(_revenueShareFactoryOverrides.contains(IERC20(factory)), _UNDEFINED_FACTORY_SHARE);

// We have checked about that the key exists, so `get` should not revert.
return _revenueShareFactoryOverrides.get(IERC20(factory), Errors.SHOULD_NOT_HAPPEN);
}

function _withdrawBpt(
IERC20 bpt,
uint256 amount,
Expand Down Expand Up @@ -231,6 +268,24 @@ contract ProtocolFeeSplitter is IProtocolFeeSplitter, SingletonAuthentication {
function _getPoolBeneficiaryFeePercentage(bytes32 poolId) private view returns (uint256) {
RevenueShareSettings memory settings = _poolSettings[poolId];

return settings.overrideSet ? settings.revenueSharePercentageOverride : _defaultRevenueSharePercentage;
if (settings.overrideSet) {
// If there is an override for this specific pool, use it.
return settings.revenueSharePercentageOverride;
}

// Is this pool from a factory with an overridden default? If so, use it.
(address poolAddress, ) = getVault().getPool(poolId);

for (uint256 i = 0; i < _revenueShareFactoryOverrides.length(); i++) {
(IERC20 factoryAddress, uint256 factoryDefaultRevenueSharePercentage) = _revenueShareFactoryOverrides
.unchecked_at(i);

if (Factory(address(factoryAddress)).isPoolFromFactory(poolAddress)) {
return factoryDefaultRevenueSharePercentage;
}
}

// If there is no override set, and no factory override, fall back to the overall default.
return _defaultRevenueSharePercentage;
}
}
Loading