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 80 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 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
2a7e078
Merge branch 'main' into factory-fee
EndymionJkb Dec 30, 2024
6cbd390
refactor: adjust to BaseVaultTest factoryMock changes
EndymionJkb Dec 30, 2024
bd967bd
feat: add BalancerContractRegistry
EndymionJkb Dec 31, 2024
7d20fef
test: add tests for BalancerContractRegistry
EndymionJkb Dec 31, 2024
cb88e34
Merge branch 'main' into contract-registry
EndymionJkb Jan 4, 2025
e334be3
feat: add OTHER category as a catch-all; rename success to isActive
EndymionJkb Jan 4, 2025
56ac5d9
Merge branch 'contract-registry' into factory-fee
EndymionJkb Jan 4, 2025
271d6c4
Merge branch 'main' into contract-registry
EndymionJkb Jan 6, 2025
d52248e
refactor: simplify data structures
EndymionJkb Jan 6, 2025
8191b9b
Merge branch 'contract-registry' into factory-fee
EndymionJkb Jan 6, 2025
90862ca
Merge branch 'main' into factory-fee
EndymionJkb Jan 14, 2025
3cbdf93
chore: update gas
EndymionJkb Jan 14, 2025
dec9eb4
Merge branch 'main' into factory-fee
EndymionJkb Jan 14, 2025
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
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 @@
231.4k
231.3k
Original file line number Diff line number Diff line change
@@ -1 +1 @@
189.4k
189.3k
Original file line number Diff line number Diff line change
@@ -1 +1 @@
222.2k
222.1k
34 changes: 21 additions & 13 deletions pkg/vault/contracts/ProtocolFeeController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ contract ProtocolFeeController is
bool isOverride;
}

// Note that the `ProtocolFeePercentagesProvider` assumes the maximum fee bounds are constant.

// Maximum protocol swap fee percentage. FixedPoint.ONE corresponds to a 100% fee.
uint256 public constant MAX_PROTOCOL_SWAP_FEE_PERCENTAGE = 50e16; // 50%

Expand Down Expand Up @@ -129,7 +131,7 @@ contract ProtocolFeeController is
if (newSwapFeePercentage > MAX_PROTOCOL_SWAP_FEE_PERCENTAGE) {
revert ProtocolSwapFeePercentageTooHigh();
}
_ensureValidPrecision(newSwapFeePercentage);
ensureValidPrecision(newSwapFeePercentage);
_;
}

Expand All @@ -138,7 +140,7 @@ contract ProtocolFeeController is
if (newYieldFeePercentage > MAX_PROTOCOL_YIELD_FEE_PERCENTAGE) {
revert ProtocolYieldFeePercentageTooHigh();
}
_ensureValidPrecision(newYieldFeePercentage);
ensureValidPrecision(newYieldFeePercentage);
_;
}

Expand All @@ -164,6 +166,11 @@ contract ProtocolFeeController is
return _vault;
}

/// @inheritdoc IProtocolFeeController
function getMaximumProtocolFeePercentages() external pure returns (uint256, uint256) {
return (MAX_PROTOCOL_SWAP_FEE_PERCENTAGE, MAX_PROTOCOL_YIELD_FEE_PERCENTAGE);
}

/// @inheritdoc IProtocolFeeController
function collectAggregateFees(address pool) public {
_vault.unlock(abi.encodeCall(ProtocolFeeController.collectAggregateFeesHook, pool));
Expand Down Expand Up @@ -521,6 +528,18 @@ contract ProtocolFeeController is
_withdrawPoolCreatorFees(pool, _poolCreators[pool]);
}

/// @inheritdoc IProtocolFeeController
function ensureValidPrecision(uint256 feePercentage) public pure {
// Primary fee percentages are 18-decimal values, stored here in 64 bits, and calculated with full 256-bit
// precision. However, the resulting aggregate fees are stored in the Vault with 24-bit precision, which
// corresponds to 0.00001% resolution (i.e., a fee can be 1%, 1.00001%, 1.00002%, but not 1.000005%).
// Ensure there will be no precision loss in the Vault - which would lead to a discrepancy between the
// aggregate fee calculated here and that stored in the Vault.
if ((feePercentage / FEE_SCALING_FACTOR) * FEE_SCALING_FACTOR != feePercentage) {
revert IVaultErrors.FeePrecisionTooHigh();
}
}

function _withdrawPoolCreatorFees(address pool, address recipient) private {
(IERC20[] memory poolTokens, uint256 numTokens) = _getPoolTokensAndCount(pool);

Expand Down Expand Up @@ -573,15 +592,4 @@ contract ProtocolFeeController is

emit ProtocolYieldFeePercentageChanged(pool, newProtocolYieldFeePercentage);
}

function _ensureValidPrecision(uint256 feePercentage) private pure {
// Primary fee percentages are 18-decimal values, stored here in 64 bits, and calculated with full 256-bit
// precision. However, the resulting aggregate fees are stored in the Vault with 24-bit precision, which
// corresponds to 0.00001% resolution (i.e., a fee can be 1%, 1.00001%, 1.00002%, but not 1.000005%).
// Ensure there will be no precision loss in the Vault - which would lead to a discrepancy between the
// aggregate fee calculated here and that stored in the Vault.
if ((feePercentage / FEE_SCALING_FACTOR) * FEE_SCALING_FACTOR != feePercentage) {
revert IVaultErrors.FeePrecisionTooHigh();
}
}
}
149 changes: 149 additions & 0 deletions pkg/vault/contracts/ProtocolFeePercentagesProvider.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.24;

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import { IProtocolFeeController } from "@balancer-labs/v3-interfaces/contracts/vault/IProtocolFeeController.sol";
import { IBasePoolFactory } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePoolFactory.sol";
import {
IProtocolFeePercentagesProvider
} from "@balancer-labs/v3-interfaces/contracts/vault/IProtocolFeePercentagesProvider.sol";
import {
IBalancerContractRegistry,
ContractType
} from "@balancer-labs/v3-interfaces/contracts/vault/IBalancerContractRegistry.sol";
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";

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

contract ProtocolFeePercentagesProvider is IProtocolFeePercentagesProvider, SingletonAuthentication {
using SafeCast for uint256;

/**
* @dev Data structure to store default protocol fees by factory. Fee percentages are 18-decimal floating point
* numbers, so we know they fit in 64 bits, allowing the fees to be stored in a single slot.
*
* @param protocolSwapFee The protocol swap fee
* @param protocolYieldFee The protocol yield fee
* @param areFactoryFeesSet Flag indicating fees have been set (allows zero values)
*/
struct FactoryProtocolFees {
uint64 protocolSwapFeePercentage;
uint64 protocolYieldFeePercentage;
bool areFactoryFeesSet;
}

IBalancerContractRegistry private immutable _trustedContractRegistry;
IProtocolFeeController private immutable _protocolFeeController;

uint256 private immutable _maxProtocolSwapFeePercentage;
uint256 private immutable _maxProtocolYieldFeePercentage;

// Factory address => FactoryProtocolFees
mapping(IBasePoolFactory => FactoryProtocolFees) private _factoryDefaultFeePercentages;

constructor(
IVault vault,
IProtocolFeeController protocolFeeController,
IBalancerContractRegistry trustedContractRegistry
) SingletonAuthentication(vault) {
_protocolFeeController = protocolFeeController;
_trustedContractRegistry = trustedContractRegistry;

if (protocolFeeController.vault() != vault) {
revert WrongProtocolFeeControllerDeployment();
}

// These values are constant in the `ProtocolFeeController`.
(_maxProtocolSwapFeePercentage, _maxProtocolYieldFeePercentage) = protocolFeeController
.getMaximumProtocolFeePercentages();
}

/// @inheritdoc IProtocolFeePercentagesProvider
function getProtocolFeeController() external view returns (IProtocolFeeController) {
return _protocolFeeController;
}

/// @inheritdoc IProtocolFeePercentagesProvider
function getFactorySpecificProtocolFeePercentages(
address factory
) external view returns (uint256 protocolSwapFeePercentage, uint256 protocolYieldFeePercentage) {
FactoryProtocolFees memory factoryFees = _getValidatedProtocolFees(factory);

protocolSwapFeePercentage = factoryFees.protocolSwapFeePercentage;
protocolYieldFeePercentage = factoryFees.protocolYieldFeePercentage;
}

/// @inheritdoc IProtocolFeePercentagesProvider
function setFactorySpecificProtocolFeePercentages(
address factory,
uint256 protocolSwapFeePercentage,
uint256 protocolYieldFeePercentage
) external authenticate {
// Validate the fee percentages; don't store values that the `ProtocolFeeCollector` will reject.
if (protocolSwapFeePercentage > _maxProtocolSwapFeePercentage) {
revert IProtocolFeeController.ProtocolSwapFeePercentageTooHigh();
}

if (protocolYieldFeePercentage > _maxProtocolYieldFeePercentage) {
revert IProtocolFeeController.ProtocolYieldFeePercentageTooHigh();
}

// Ensure precision checks will pass.
_protocolFeeController.ensureValidPrecision(protocolSwapFeePercentage);
_protocolFeeController.ensureValidPrecision(protocolYieldFeePercentage);

// Ensure the factory is valid.
if (_trustedContractRegistry.isActiveBalancerContract(ContractType.POOL_FACTORY, factory) == false) {
revert UnknownFactory(factory);
}

// Store the default fee percentages, and mark the factory as registered.
_factoryDefaultFeePercentages[IBasePoolFactory(factory)] = FactoryProtocolFees({
protocolSwapFeePercentage: protocolSwapFeePercentage.toUint64(),
elshan-eth marked this conversation as resolved.
Show resolved Hide resolved
protocolYieldFeePercentage: protocolYieldFeePercentage.toUint64(),
areFactoryFeesSet: true
});

emit FactorySpecificProtocolFeePercentagesSet(factory, protocolSwapFeePercentage, protocolYieldFeePercentage);
}

/// @inheritdoc IProtocolFeePercentagesProvider
function setProtocolFeePercentagesForPools(address factory, address[] memory pools) external {
FactoryProtocolFees memory factoryFees = _getValidatedProtocolFees(factory);

for (uint256 i = 0; i < pools.length; ++i) {
address currentPool = pools[i];

if (IBasePoolFactory(factory).isPoolFromFactory(currentPool) == false) {
elshan-eth marked this conversation as resolved.
Show resolved Hide resolved
revert PoolNotFromFactory(currentPool, factory);
}

_setPoolProtocolFees(
currentPool,
factoryFees.protocolSwapFeePercentage,
factoryFees.protocolYieldFeePercentage
);
}
}

function _getValidatedProtocolFees(address factory) private view returns (FactoryProtocolFees memory factoryFees) {
factoryFees = _factoryDefaultFeePercentages[IBasePoolFactory(factory)];

if (factoryFees.areFactoryFeesSet == false) {
revert FactoryFeesNotSet(factory);
}
}

// These are permissioned functions on `ProtocolFeeController`, so governance will need to allow this contract
// to call `setProtocolSwapFeePercentage` and `setProtocolYieldFeePercentage`.
function _setPoolProtocolFees(
address pool,
uint256 protocolSwapFeePercentage,
uint256 protocolYieldFeePercentage
) private {
_protocolFeeController.setProtocolSwapFeePercentage(pool, protocolSwapFeePercentage);
_protocolFeeController.setProtocolYieldFeePercentage(pool, protocolYieldFeePercentage);
}
}
4 changes: 4 additions & 0 deletions pkg/vault/contracts/test/PoolFactoryMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ contract PoolFactoryMock is IBasePoolFactory, SingletonAuthentication, FactoryWi
);
}

function manualSetPoolFromFactory(address pool) external {
_isPoolFromFactory[pool] = true;
}

function _getDefaultLiquidityManagement() private pure returns (LiquidityManagement memory) {
LiquidityManagement memory liquidityManagement;
liquidityManagement.enableAddLiquidityCustom = true;
Expand Down
8 changes: 8 additions & 0 deletions pkg/vault/test/foundry/ProtocolFeeController.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ contract ProtocolFeeControllerTest is BaseVaultTest {
assertEq(feeAmounts[1], 0, "Collected creator fee amount [1] is non-zero");
}

function testGetMaximumProtocolFeePercentages() public view {
(uint256 maxSwapFeePercentage, uint256 maxYieldFeePercentage) = feeController
.getMaximumProtocolFeePercentages();

assertEq(maxSwapFeePercentage, MAX_PROTOCOL_SWAP_FEE_PCT, "Wrong maximum swap fee percentage");
assertEq(maxYieldFeePercentage, MAX_PROTOCOL_YIELD_FEE_PCT, "Wrong maximum yield fee percentage");
}

function testSetGlobalProtocolSwapFeePercentageRange() public {
authorizer.grantRole(
feeControllerAuth.getActionId(IProtocolFeeController.setGlobalProtocolSwapFeePercentage.selector),
Expand Down
Loading
Loading