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

Add helper to set protocol fees by factory #897

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
8ade135
checkpoint
EndymionJkb Aug 17, 2024
37e7d85
Merge branch 'main' into factory-fee
EndymionJkb Aug 17, 2024
11e2a7e
Merge branch 'main' into factory-fee
EndymionJkb Aug 17, 2024
d354182
checkpoint - most general
EndymionJkb Aug 17, 2024
963b158
refactor: add interface, and simplify (remove completely generic pool…
EndymionJkb Aug 18, 2024
507dfb5
lint
EndymionJkb Aug 18, 2024
68b65e2
test: add tests for new fee controller getter
EndymionJkb Aug 18, 2024
b2089b6
test: add percentages provider tests
EndymionJkb Aug 18, 2024
d384e0e
docs: clarify permission requirements
EndymionJkb Aug 18, 2024
0814c98
refactor: use constants in test instead of hard-coding
EndymionJkb Aug 18, 2024
9e9a6f2
refactor: remove unnecessary permission set
EndymionJkb Aug 18, 2024
4b2d40d
refactor: add event
EndymionJkb Aug 19, 2024
e428ffd
Merge branch 'main' into factory-fee
EndymionJkb Aug 23, 2024
1301cd4
Merge branch 'main' into factory-fee
EndymionJkb Aug 23, 2024
b1552f0
Merge branch 'main' into factory-fee
EndymionJkb Aug 26, 2024
c4bcf2c
Merge branch 'main' into factory-fee
EndymionJkb Aug 27, 2024
b0b09f5
Merge branch 'main' into factory-fee
EndymionJkb Aug 28, 2024
557b97d
chore: update gas
EndymionJkb Aug 28, 2024
9310d7e
Merge branch 'main' into factory-fee
EndymionJkb Aug 28, 2024
7e44de5
Merge branch 'main' into factory-fee
EndymionJkb Aug 28, 2024
13658d0
Merge branch 'main' into factory-fee
EndymionJkb Aug 28, 2024
d559356
Merge branch 'main' into factory-fee
EndymionJkb Aug 30, 2024
227a52e
Merge branch 'main' into factory-fee
EndymionJkb Aug 30, 2024
0dd8cbf
Merge branch 'main' into factory-fee
EndymionJkb Sep 1, 2024
2ba62a0
Merge branch 'main' into factory-fee
EndymionJkb Sep 2, 2024
f99fb6e
Merge branch 'main' into factory-fee
EndymionJkb Sep 2, 2024
5ce27b3
Merge branch 'main' into factory-fee
EndymionJkb Sep 2, 2024
e4c32d4
fix: import
EndymionJkb Sep 2, 2024
a621374
Merge branch 'main' into factory-fee
EndymionJkb Sep 4, 2024
81da628
refactor: expose the precision check
EndymionJkb Sep 4, 2024
fa46b99
feat: validate precision in percentages provider
EndymionJkb Sep 4, 2024
77591d5
Merge branch 'main' into factory-fee
EndymionJkb Sep 4, 2024
a089892
Merge branch 'main' into factory-fee
EndymionJkb Sep 12, 2024
8e99571
Merge branch 'main' into factory-fee
EndymionJkb Sep 12, 2024
e3be8ee
Merge branch 'main' into factory-fee
EndymionJkb Sep 16, 2024
b2556d4
Merge branch 'main' into factory-fee
EndymionJkb Sep 18, 2024
d243d8c
Merge branch 'main' into factory-fee
EndymionJkb Sep 19, 2024
18f1a51
Merge branch 'main' into factory-fee
EndymionJkb Sep 20, 2024
d02643f
Merge branch 'main' into factory-fee
EndymionJkb Sep 23, 2024
2def1d8
Merge branch 'main' into factory-fee
EndymionJkb Sep 24, 2024
6b0a96c
Merge branch 'main' into factory-fee
EndymionJkb Sep 24, 2024
2a78301
Merge branch 'main' into factory-fee
EndymionJkb Sep 25, 2024
01f9464
Merge branch 'main' into factory-fee
EndymionJkb Sep 27, 2024
0c62abc
Merge branch 'main' into factory-fee
EndymionJkb Sep 27, 2024
048182c
Merge branch 'main' into factory-fee
EndymionJkb Oct 1, 2024
92a2828
Merge branch 'main' into factory-fee
EndymionJkb Oct 3, 2024
f25cc1a
Merge branch 'main' into factory-fee
EndymionJkb Oct 9, 2024
3917321
Merge branch 'main' into factory-fee
EndymionJkb Oct 9, 2024
4e5467c
Merge branch 'main' into factory-fee
EndymionJkb Oct 9, 2024
56c98e0
Merge branch 'main' into factory-fee
EndymionJkb Oct 14, 2024
c178a85
Merge branch 'main' into factory-fee
EndymionJkb Oct 16, 2024
e2c454f
Merge branch 'main' into factory-fee
EndymionJkb Oct 18, 2024
a36b105
Merge branch 'main' into factory-fee
EndymionJkb Oct 24, 2024
322f040
Merge branch 'main' into factory-fee
EndymionJkb Oct 31, 2024
084eb19
Merge branch 'main' into factory-fee
EndymionJkb Nov 8, 2024
17afc3d
Merge branch 'main' into factory-fee
EndymionJkb Nov 12, 2024
adcd30c
Merge branch 'main' into factory-fee
EndymionJkb Nov 15, 2024
5c4d65e
Merge branch 'main' into factory-fee
EndymionJkb Nov 20, 2024
4f7a554
Merge branch 'main' into factory-fee
EndymionJkb Dec 6, 2024
20fdd85
fix: update constant names
EndymionJkb Dec 9, 2024
1e6b536
Merge branch 'main' into factory-fee
EndymionJkb Dec 10, 2024
845d0e8
Merge branch 'main' into factory-fee
EndymionJkb Dec 12, 2024
f67bd8c
Add registry of "trusted" contracts (#1179)
EndymionJkb Dec 17, 2024
78f5e33
Merge branch 'main' into factory-fee
EndymionJkb Dec 18, 2024
2de3fee
chore: update bytecode
EndymionJkb Dec 18, 2024
2a838bf
chore: update gas
EndymionJkb Dec 18, 2024
5b5a780
Merge branch 'main' into factory-fee
EndymionJkb Dec 24, 2024
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
159 changes: 159 additions & 0 deletions pkg/interfaces/contracts/vault/IBalancerContractRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.24;

/// @notice Registered contracts must be one of these types.
enum ContractType {
POOL_FACTORY,
ROUTER,
HOOK,
ERC4626
}

interface IBalancerContractRegistry {
/**
* @notice Contracts can be deprecated, so we store an active flag indicating the status.
* @dev With two flags, we can differentiate between deprecated and non-existent.
* @param exists This flag indicates whether there is an entry for the address or not
* @param active If there is an entry, this flag indicates whether it is active or deprecated
*/
struct ContractStatus {
bool exists;
bool active;
}

/**
* @notice Emitted wen a new contract is registered.
* @param contractType The type of contract being registered
* @param contractName The name of the contract
* @param contractAddress The address of the contract being registered
*/
event BalancerContractRegistered(
ContractType indexed contractType,
string indexed contractName,
address indexed contractAddress
);

/**
* @notice Emitted when a new contract is deprecated.
* @dev This sets the `active` flag to false.
* @param contractAddress The address of the contract being deprecated
*/
event BalancerContractDeprecated(address indexed contractAddress);

/**
* @notice Emitted when a new contract is deprecated.
* @dev This sets the `active` flag to false.
* @param contractType The type of contract being registered
* @param contractName The name of the contract
* @param existingContract The address of the old contract being replaced
* @param newContract The address of new contract
*/
event BalancerContractReplaced(
ContractType indexed contractType,
string indexed contractName,
address existingContract,
address newContract
);

/**
* @notice The given type and name have already been registered.
* @dev Note that the same address can be registered multiple times under different names. For instance, we might
* register an address as both "Factory/20241205-v3-weighted-pool" and "Factory/WeightedPool", or
* "Hook/StableSurgeHook" and "Router/StableSurgeHook". However, the combination of type and name must be unique.
*
* @param contractType The type of the contract
* @param contractName The name of the contract
*/
error ContractAlreadyRegistered(ContractType contractType, string contractName);

/// @notice The contract being deprecated was never registered.
error ContractNotRegistered();

/**
* @notice The contract being deprecated was registered, but already deprecated.
* @param contractAddress The address of the contract to be deprecated
*/
error ContractAlreadyDeprecated(address contractAddress);

/// @notice Registered contracts cannot have the zero address.
error ZeroContractAddress();

/// @notice Registered contract names cannot be blank.
error InvalidContractName();

/**
* @notice Register an official Balancer contract (e.g., a trusted router, standard pool factory, or hook).
* @dev This is a permissioned function, and does only basic validation of the address (non-zero) and the name
* (not blank). Governance must ensure this is called with valid information. Emits the
* `BalancerContractRegistered` event if successful. Reverts if the name or address is invalid, or the type/name
* combination has already been registered.
*
* @param contractType The type of contract being registered
* @param contractName A text description of the contract (e.g., "WeightedPool")
* @param contractAddress The address of the contract
*/
function registerBalancerContract(
ContractType contractType,
string memory contractName,
address contractAddress
) external;

/**
* @notice Deprecate an official Balancer contract.
* @dev This is a permissioned function that sets the `active` flag to false. The same address might be registered
* multiple times (i.e., unique combinations of types and names); deprecating the address will naturally apply to
* all of them. Emits an `BalancerContractDeprecated` event if successful. Reverts if the address has not been
* registered, or has already been deprecated.
*
* @param contractAddress The address of the contract being deregistered
*/
function deprecateBalancerContract(address contractAddress) external;

/**
* @notice Migrate a named contract to a new address.
* @dev This is a permissioned function, intended to address one edge case and one feature. The edge case is
* handling mistakes. If an address is mistakenly registered (e.g., set to the address on a different chain),
* this allows correction. The feature is supporting querying for the "latest" contract (e.g., the latest version
* of `WeightedPoolFactory`), vs. having to know the exact version. If the "latest" contract address changes --
* for instance, if we deprecated `v3-weighted-pool` and registered `v3-weighted-pool-v2`, we would need to
* update `WeightedPoolFactory` to point to the v2 address. Normal registration would fail, as that combination
* was already registered, pointing to v1.
*
* @param contractType The type of contract being replaced
* @param contractName The name of the contract being replaced
* @param newContractAddress The address of the contract that should replace the existing registration
*/
function replaceBalancerContract(
ContractType contractType,
string memory contractName,
address newContractAddress
) external;

/**
* @notice Determine whether an address is an official contract of the specified type.
* @dev This is a permissioned function.
* @param contractType The type of contract being renamed
* @param contractAddress The address of the contract
* @return success True if the given address is a registered and active contract of the specified type
*/
function isActiveBalancerContract(
ContractType contractType,
address contractAddress
) external view returns (bool success);

/**
* @notice Lookup a registered contract by type and name
* @dev This could target a particular version (e.g. `20241205-v3-weighted-pool`), or a contract name
* (e.g., `WeightedPool`), which could return the "latest" WeightedPool deployment.
*
* @param contractType The type of the contract
* @param contractName The name of the contract
* @return contractAddress The address of the associated contract, if registered, or zero
* @return active True if the address was registered and not deprecated
*/
function getBalancerContract(
ContractType contractType,
string memory contractName
) external view returns (address contractAddress, bool active);
}
14 changes: 14 additions & 0 deletions pkg/interfaces/contracts/vault/IProtocolFeeController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ interface IProtocolFeeController {
*/
function vault() external view returns (IVault);

/**
* @notice Return the maximum swap and yield protocol fee percentages.
* @return maxProtocolSwapFeePercentage The maximum protocol swap fee percentage
* @return maxProtocolYieldFeePercentage The maximum protocol yield fee percentage
*/
function getMaximumProtocolFeePercentages() external pure returns (uint256, uint256);

/**
* @notice Collects aggregate fees from the Vault for a given pool.
* @param pool The pool with aggregate fees
Expand Down Expand Up @@ -227,6 +234,13 @@ interface IProtocolFeeController {
*/
function updateProtocolYieldFeePercentage(address pool) external;

/**
* @notice Ensure the proposed fee can be stored in the Vault without precision loss.
* @dev Fees are stored with 24 bit precision. The function will revert with `FeePrecisionTooHigh` if invalid.
* @param feePercentage The percentage to be checked
*/
function ensureValidPrecision(uint256 feePercentage) external pure;

/***************************************************************************
Permissioned Functions
***************************************************************************/
Expand Down
88 changes: 88 additions & 0 deletions pkg/interfaces/contracts/vault/IProtocolFeePercentagesProvider.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.24;

import { IProtocolFeeController } from "./IProtocolFeeController.sol";

interface IProtocolFeePercentagesProvider {
/**
* @notice Protocol fee percentages have been set for the given factory.
* @param factory The pool factory
* @param protocolSwapFeePercentage The protocol swap fee percentage intended for pools from this factory
* @param protocolYieldFeePercentage The protocol yield fee percentage intended for pools from this factory
*/
event FactorySpecificProtocolFeePercentagesSet(
address indexed factory,
uint256 protocolSwapFeePercentage,
uint256 protocolYieldFeePercentage
);

/// @notice The protocol fee controller was configured with an incorrect Vault address.
error WrongProtocolFeeControllerDeployment();

/**
* @notice Fees can only be set on recognized factories (i.e., registered in the `BalancerContractRegistry`).
* @param factory The address of the unknown factory
*/
error UnknownFactory(address factory);

/**
* @notice `setFactorySpecificProtocolFeePercentages` has not been called for this factory address.
* @dev This error can by thrown by `getFactorySpecificProtocolFeePercentages` or
* `setProtocolFeePercentagesForPools`, as both require that valid fee percentages have been set.
* You need to set the factory fees before you can apply them to pools from that factory.
*
* @param factory The factory address where fees have not been set
*/
error FactoryFeesNotSet(address factory);

/**
* @notice The given pool is not from the expected factory.
* @dev Occurs when one of the pools supplied to `setProtocolFeePercentagesForPools` is not from the given factory.
* @param pool The address of the unrecognized pool
* @param factory The address of the factory
*/
error PoolNotFromFactory(address pool, address factory);

/**
* @notice Get the address of the `ProtocolFeeController` used to set fees.
* @return protocolFeeController The address of the fee controller
*/
function getProtocolFeeController() external view returns (IProtocolFeeController);

/**
* @notice Query the protocol fee percentages for a given factory.
* @param factory The address of the factory
* @return protocolSwapFeePercentage The protocol swap fee percentage set for that factory
* @return protocolYieldFeePercentage The protocol yield fee percentage set for that factory
*/
function getFactorySpecificProtocolFeePercentages(
address factory
) external view returns (uint256 protocolSwapFeePercentage, uint256 protocolYieldFeePercentage);

/**
* @notice Assign intended protocol fee percentages for a given factory.
* @dev This is a permissioned call. After the fee percentages have been set, and governance has granted
* this contract permission to set fee percentages on pools, anyone can call `setProtocolFeePercentagesForPools`
* to update the fee percentages on a set of pools from that factory.
*
* @param factory The address of the factory
* @param protocolSwapFeePercentage The new protocol swap fee percentage
* @param protocolYieldFeePercentage The new protocol yield fee percentage
*/
function setFactorySpecificProtocolFeePercentages(
address factory,
uint256 protocolSwapFeePercentage,
uint256 protocolYieldFeePercentage
) external;

/**
* @notice Update the protocol fees for a set of pools from a given factory.
* @dev This call is permissionless. Anyone can update the fee percentages, once they're set by governance.
* Note that governance must also grant this contract permission to set protocol fee percentages on pools.
*
* @param factory The address of the factory
* @param pools The pools whose fees will be set according to `setFactorySpecificProtocolFeePercentages`
*/
function setProtocolFeePercentagesForPools(address factory, address[] memory pools) external;
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174.0k
174.1k
Loading
Loading