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

Protocol Fee Controller migration contract #1299

Merged
merged 57 commits into from
Mar 8, 2025
Merged
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
a062f77
feat: add getters for pool creator data, and explicit pool registrati…
EndymionJkb Feb 16, 2025
529ac79
feat: add governance-scripts package
EndymionJkb Feb 16, 2025
b058b23
feat: add protocol fee controller migration
EndymionJkb Feb 16, 2025
b30b537
refactor: don't pass in pool creator to initialize
EndymionJkb Feb 16, 2025
eed79d8
refactor: remove directory that generates strange errors
EndymionJkb Feb 17, 2025
33ce5e6
refactor: remove redundant (and problematic) `_poolCreators` storage
EndymionJkb Feb 17, 2025
ab3df83
refactor: remove unused error
EndymionJkb Feb 17, 2025
395c7bc
refactor: don't collect and withdraw fees
EndymionJkb Feb 17, 2025
8d4409d
feat: add explicit pool registration and new pool creator event
EndymionJkb Feb 17, 2025
71b466b
test: add tests for new features
EndymionJkb Feb 17, 2025
42be536
docs: update migration comments for simple one
EndymionJkb Feb 17, 2025
ccae6fd
feat: add registerInMigration helper
EndymionJkb Feb 17, 2025
22102e1
test: add tests for new migration function
EndymionJkb Feb 17, 2025
01a081c
feat: add level 2 migration contract
EndymionJkb Feb 17, 2025
7ebb82f
refactor: simplify to pass old fee controller instead of the values (…
EndymionJkb Feb 18, 2025
a7999dd
test: new migration interface
EndymionJkb Feb 18, 2025
746a210
refactor: reuse original migration functions
EndymionJkb Feb 18, 2025
dff7d50
refactor: rename migration function
EndymionJkb Feb 18, 2025
f8e9652
refactor: add migration role
EndymionJkb Feb 18, 2025
57d48d2
refactor: simplify migrations
EndymionJkb Feb 18, 2025
da0e2b9
refactor: simplify migratePool
EndymionJkb Feb 18, 2025
c00dccc
lint
EndymionJkb Feb 18, 2025
90adc71
refactor: don't need FixedPoint
EndymionJkb Feb 18, 2025
570a075
test: adjust to new migration signature
EndymionJkb Feb 18, 2025
56d791d
test: remove unnecessary pool creator storage from fee controller
EndymionJkb Feb 18, 2025
25b8162
refactor: make virtual in case we need a v3 someday
EndymionJkb Feb 18, 2025
ecb07f0
Merge branch 'main' into fee-controller-script
EndymionJkb Feb 18, 2025
e7c6149
refactor: move basic authorizer
EndymionJkb Feb 18, 2025
c735ec2
refactor: complete move of basic authorizer
EndymionJkb Feb 18, 2025
3b04170
Merge branch 'main' into fee-controller-script
EndymionJkb Feb 18, 2025
c4639be
feat: new protocol fee controller, suitable for migrations
EndymionJkb Feb 19, 2025
4da42c5
test: update tests for new functions
EndymionJkb Feb 19, 2025
c4324fb
refactor: remove pool creator from ProtocolFeeControllerMock
EndymionJkb Feb 19, 2025
0a5c484
chore: update bytecode
EndymionJkb Feb 19, 2025
ebae2ab
chore: update gas
EndymionJkb Feb 19, 2025
7793e6d
docs: fix comments and decrease diffs
EndymionJkb Feb 19, 2025
c1be315
Merge branch 'protocol-fee-controller-v2' into fee-controller-script
EndymionJkb Feb 19, 2025
0e8bd5a
test: adjust tests for fee controller pool creator
EndymionJkb Feb 19, 2025
84f0b1e
Merge branch 'protocol-fee-controller-v2' into fee-controller-script
EndymionJkb Feb 19, 2025
cde1d1e
refactor: remove unnecessary import
EndymionJkb Feb 19, 2025
2f14d8b
Merge branch 'protocol-fee-controller-v2' into fee-controller-script
EndymionJkb Feb 19, 2025
27da6d2
Merge branch 'main' into protocol-fee-controller-v2
EndymionJkb Feb 19, 2025
d52eb97
Merge branch 'protocol-fee-controller-v2' into fee-controller-script
EndymionJkb Feb 19, 2025
af318e8
Merge branch 'main' into fee-controller-script
EndymionJkb Feb 20, 2025
b62843d
refactor: migratePools is now permissionless
EndymionJkb Feb 20, 2025
1510a2d
Merge branch 'main' into fee-controller-script
EndymionJkb Feb 21, 2025
9eff06c
temp: to accommodate fork tests, allow the fee controller to be set l…
EndymionJkb Feb 21, 2025
2086a6b
refactor: reduce to a single migration script
EndymionJkb Feb 22, 2025
e3dae99
refactor: tolerate missing pool creator fee percentage getters
EndymionJkb Feb 22, 2025
7a33dd2
Merge branch 'protocol-fee-controller-v3' into fee-controller-script
EndymionJkb Feb 22, 2025
940dcaa
docs: clarify comments
EndymionJkb Feb 22, 2025
b1edecc
Merge branch 'main' into fee-controller-script
EndymionJkb Feb 28, 2025
991f2d7
remove temporary debugging code
EndymionJkb Feb 28, 2025
a18f9c3
Merge branch 'main' into fee-controller-script
EndymionJkb Mar 6, 2025
b4120b8
Merge branch 'main' into fee-controller-script
EndymionJkb Mar 7, 2025
329d986
docs: remove blank line
EndymionJkb Mar 8, 2025
db892cb
docs: fix comment
EndymionJkb Mar 8, 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
Prev Previous commit
Next Next commit
feat: add level 2 migration contract
EndymionJkb committed Feb 17, 2025
commit 01a081ca3eb02731f06b34df044270caaa093cc2
161 changes: 161 additions & 0 deletions pkg/governance-scripts/contracts/ProtocolFeeControllerMigrationV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.24;

import { IAuthentication } from "@balancer-labs/v3-interfaces/contracts/solidity-utils/helpers/IAuthentication.sol";
import { IProtocolFeeController } from "@balancer-labs/v3-interfaces/contracts/vault/IProtocolFeeController.sol";
import { PoolRoleAccounts, PoolConfig } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";
import { IVaultAdmin } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultAdmin.sol";
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";

import { SingletonAuthentication } from "@balancer-labs/v3-vault/contracts/SingletonAuthentication.sol";
import { ProtocolFeeController } from "@balancer-labs/v3-vault/contracts/ProtocolFeeController.sol";
import {
ReentrancyGuardTransient
} from "@balancer-labs/v3-solidity-utils/contracts/openzeppelin/ReentrancyGuardTransient.sol";
import { FixedPoint } from "@balancer-labs/v3-solidity-utils/contracts/math/FixedPoint.sol";

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

/**
* @notice Migrate from the original ProtocolFeeController to one with extra events.
* @dev These events enable tracking pool protocol fees under all circumstances (in particular, when protocol fees are
* initially turned off).
*
* After deployment, call `migratePools` as many times as necessary. The list must be generated externally, as pools
* are not iterable on-chain. The batch interface allows an unlimited number of pools to be migrated; it's possible
* there might be too many to migrate in a single call.
*
* The first time `migratePools` is called, the contract will first copy the global (pool-independent data). This could
* be done in a separate stage, but we're trying to keep the contract simple, vs. duplicating the staging coordinator
* system of v2 just yet.
*
* When all pools have been migrated, call `finalizeMigration` to disable further migration, update the address in the
* Vault, and renounce all permissions. While `migratePools` is permissionless, this call must be permissioned to
* prevent premature termination in case multiple transactions are required to migrate all the pools.
*
* Associated with `20250221-protocol-fee-controller-migration` (fork test only).
*/
contract ProtocolFeeControllerMigrationV2 is SingletonAuthentication, ReentrancyGuardTransient {
using FixedPoint for uint256;

IProtocolFeeController public immutable oldFeeController;
IProtocolFeeController public immutable newFeeController;

IVault public immutable vault;

// IAuthorizer with interface for granting/revoking roles.
IBasicAuthorizer internal immutable _authorizer;

// Set after the global percentages have been transferred (on the first call to `migratePools`).
bool private _globalPercentagesMigrated;

// Set when the operation is complete and all permissions have been renounced.
bool private _finalized;

/**
* @notice Attempt to deploy this contract with invalid parameters.
* @dev ProtocolFeeController contracts return the address of the Vault they were deployed with. Ensure that both
* the old and new controllers reference the same vault.
*/
error InvalidFeeController();

/// @notice Migration can only be performed once.
error AlreadyMigrated();

constructor(
IVault _vault,
IProtocolFeeController _oldFeeController,
IProtocolFeeController _newFeeController
) SingletonAuthentication(_oldFeeController.vault()) {
IVault oldControllerVault = _oldFeeController.vault();

// Ensure valid fee controllers.
if (_newFeeController.vault() != oldControllerVault || _vault != oldControllerVault) {
revert InvalidFeeController();
}

vault = _vault;
oldFeeController = _oldFeeController;
newFeeController = _newFeeController;

_authorizer = IBasicAuthorizer(address(vault.getAuthorizer()));
}

function migratePools(address[] memory pools) external nonReentrant {
if (_finalized) {
revert AlreadyMigrated();
}

if (_globalPercentagesMigrated == false) {
_globalPercentagesMigrated = true;

_migrateGlobalPercentages();
}

// This more complex migration allows for pool creators and overrides, and uses the new features in the second
// deployment of the `ProtocolFeeController`.
//
// At the end of this process, governance must still withdraw any leftover protocol fees from the old
// controller (i.e., that have been collected but not withdrawn). Pool creators likewise would still need to
// withdraw any leftover pool creator fees from the old controller.
for (uint256 i = 0; i < pools.length; ++i) {
_migratePool(pools[i]);
}
}

function finalizeMigration() external authenticate {
if (_finalized) {
revert AlreadyMigrated();
}

_finalized = true;

// Update the fee controller in the Vault.
_migrateFeeController();

// Revoke all permissions.
_authorizer.renounceRole(_authorizer.DEFAULT_ADMIN_ROLE(), address(this));
}

function _migrateGlobalPercentages() private {
// Grant global fee percentage permissions to set on new controller.
bytes32 swapFeeRole = IAuthentication(address(newFeeController)).getActionId(
IProtocolFeeController.setGlobalProtocolSwapFeePercentage.selector
);

bytes32 yieldFeeRole = IAuthentication(address(newFeeController)).getActionId(
IProtocolFeeController.setGlobalProtocolYieldFeePercentage.selector
);

_authorizer.grantRole(swapFeeRole, address(this));
_authorizer.grantRole(yieldFeeRole, address(this));

// Copy percentages to new controller.
uint256 globalSwapFeePercentage = oldFeeController.getGlobalProtocolSwapFeePercentage();
uint256 globalYieldFeePercentage = oldFeeController.getGlobalProtocolYieldFeePercentage();

newFeeController.setGlobalProtocolSwapFeePercentage(globalSwapFeePercentage);
newFeeController.setGlobalProtocolYieldFeePercentage(globalYieldFeePercentage);

// Revoke permissions.
_authorizer.renounceRole(swapFeeRole, address(this));
_authorizer.renounceRole(yieldFeeRole, address(this));
}

function _migratePool(address pool) internal {

}

function _migrateFeeController() internal {
bytes32 setFeeControllerRole = IAuthentication(address(vault)).getActionId(
IVaultAdmin.setProtocolFeeController.selector
);

_authorizer.grantRole(setFeeControllerRole, address(this));

vault.setProtocolFeeController(newFeeController);

_authorizer.renounceRole(setFeeControllerRole, address(this));
}
}