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

fix: replace guardianModule addr with opsMultisig for VT purchase with pufETH #75

Merged
merged 2 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion mainnet-contracts/script/DeployPuffer.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ contract DeployPuffer is BaseScript {
address rewardsCoordinator;
address eigenSlasher;
address treasury;
address operationsMultisig;

function run(GuardiansDeployment calldata guardiansDeployment, address pufferVault, address oracle)
public
Expand All @@ -77,20 +78,23 @@ contract DeployPuffer is BaseScript {
eigenSlasher = 0xD92145c07f8Ed1D392c1B88017934E301CC1c3Cd;
rewardsCoordinator = address(0); //@todo
treasury = vm.envAddress("TREASURY");
operationsMultisig = 0xC0896ab1A8cae8c2C1d27d011eb955Cca955580d;
} else if (isAnvil()) {
// Local chain / tests
eigenPodManager = address(new EigenPodManagerMock());
delegationManager = address(new DelegationManagerMock());
rewardsCoordinator = address(new RewardsCoordinatorMock());
eigenSlasher = vm.envOr("EIGEN_SLASHER", address(1)); // @todo
treasury = address(1);
operationsMultisig = address(2);
} else {
// Holesky https://github.com/Layr-Labs/eigenlayer-contracts?tab=readme-ov-file#current-testnet-deployment
eigenPodManager = 0x30770d7E3e71112d7A6b7259542D1f680a70e315;
delegationManager = 0xA44151489861Fe9e3055d95adC98FbD462B948e7;
eigenSlasher = 0xcAe751b75833ef09627549868A04E32679386e7C;
treasury = 0x61A44645326846F9b5d9c6f91AD27C3aD28EA390;
rewardsCoordinator = 0xAcc1fb458a1317E886dB376Fc8141540537E68fE;
operationsMultisig = 0xDDDeAfB492752FC64220ddB3E7C9f1d5CcCdFdF0;
}

operationsCoordinator = new OperationsCoordinator(PufferOracleV2(oracle), address(accessManager), 500); // 500 BPS = 5%
Expand All @@ -101,7 +105,8 @@ contract DeployPuffer is BaseScript {
guardianModule: payable(guardiansDeployment.guardianModule),
treasury: payable(treasury),
pufferVault: payable(pufferVault),
pufferOracle: IPufferOracleV2(oracle)
pufferOracle: IPufferOracleV2(oracle),
operationsMultisig: operationsMultisig
});

NoImplementation(payable(address(validatorTicketProxy))).upgradeToAndCall(
Expand Down
3 changes: 2 additions & 1 deletion mainnet-contracts/script/DeployVTImplementation.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ contract DeployVTImplementation is DeployerHelper {
guardianModule: payable(address(_getGuardianModule())),
treasury: payable(_getTreasury()),
pufferVault: payable(_getPufferVault()),
pufferOracle: IPufferOracle(address(_getPufferOracle()))
pufferOracle: IPufferOracle(address(_getPufferOracle())),
operationsMultisig: _getOPSMultisig()
});

//@todo Double check reinitialization
Expand Down
3 changes: 2 additions & 1 deletion mainnet-contracts/script/UpgradeValidatorTicket.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ contract UpgradeValidatorTicket is DeployerHelper {
guardianModule: payable(address(_getGuardianModule())),
treasury: payable(_getTreasury()),
pufferVault: payable(_getPufferVault()),
pufferOracle: IPufferOracle(address(_getPufferOracle()))
pufferOracle: IPufferOracle(address(_getPufferOracle())),
operationsMultisig: _getOPSMultisig()
});

validatorTicket = ValidatorTicket(payable(_getValidatorTicket()));
Expand Down
14 changes: 12 additions & 2 deletions mainnet-contracts/src/ValidatorTicket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ contract ValidatorTicket is
*/
IPufferOracle public immutable override PUFFER_ORACLE;

/**
* @inheritdoc IValidatorTicket
*/
address public immutable override OPERATIONS_MULTISIG;

/**
* @dev Basis point scale
*/
Expand All @@ -68,7 +73,8 @@ contract ValidatorTicket is
address payable guardianModule,
address payable treasury,
address payable pufferVault,
IPufferOracle pufferOracle
IPufferOracle pufferOracle,
address operationsMultisig
) {
if (
guardianModule == address(0) || treasury == address(0) || pufferVault == address(0)
Expand All @@ -80,6 +86,7 @@ contract ValidatorTicket is
GUARDIAN_MODULE = guardianModule;
PUFFER_VAULT = pufferVault;
TREASURY = treasury;
OPERATIONS_MULTISIG = operationsMultisig;
_disableInitializers();
}

Expand Down Expand Up @@ -249,6 +256,9 @@ contract ValidatorTicket is

/**
* @dev Internal function to process the purchase of Validator Tickets with pufETH
* @notice The guardians' portion of pufETH fees is sent to the Operations Multisig since the
* GuardianModule cannot handle ERC20-compatible pufETH. This differs from ETH purchases where
* the guardians' portion goes directly to the GuardianModule.
* @param recipient The address to receive the minted VTs
* @param vtAmount The amount of Validator Tickets to purchase
* @return pufEthUsed The amount of pufETH used for the purchase
Expand Down Expand Up @@ -279,7 +289,7 @@ contract ValidatorTicket is
ValidatorTicket storage $ = _getValidatorTicketStorage();

uint256 treasuryAmount = _sendPufETH(TREASURY, pufEthUsed, $.protocolFeeRate);
uint256 guardiansAmount = _sendPufETH(GUARDIAN_MODULE, pufEthUsed, $.guardiansFeeRate);
uint256 guardiansAmount = _sendPufETH(OPERATIONS_MULTISIG, pufEthUsed, $.guardiansFeeRate);
uint256 burnAmount = pufEthUsed - (treasuryAmount + guardiansAmount);

PufferVaultV3(PUFFER_VAULT).burn(burnAmount);
Expand Down
5 changes: 5 additions & 0 deletions mainnet-contracts/src/interface/IValidatorTicket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ interface IValidatorTicket {
*/
function PUFFER_ORACLE() external view returns (IPufferOracle);

/**
* @notice Returns the Operations Multisig
*/
function OPERATIONS_MULTISIG() external view returns (address);

/**
* @notice Retrieves the current protocol fee rate
* @return The current protocol fee rate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract ValidatorTicketMainnetTest is MainnetForkTestHelper {
uint256 public constant INITIAL_GUARDIANS_FEE = 50; // 0.5%

function setUp() public override {
vm.createSelectFork(vm.rpcUrl("mainnet"), 21074115);
vm.createSelectFork(vm.rpcUrl("mainnet"), 21120959);

// Label accounts for better trace output
for (uint256 i = 0; i < TOKEN_HOLDERS.length; i++) {
Expand Down Expand Up @@ -58,6 +58,7 @@ contract ValidatorTicketMainnetTest is MainnetForkTestHelper {
assertTrue(validatorTicket.GUARDIAN_MODULE() != address(0));
assertTrue(validatorTicket.PUFFER_VAULT() != address(0));
assertTrue(validatorTicket.TREASURY() != address(0));
assertTrue(validatorTicket.OPERATIONS_MULTISIG() != address(0));
}

function test_purchase_validator_ticket_with_pufeth() public {
Expand Down Expand Up @@ -86,7 +87,7 @@ contract ValidatorTicketMainnetTest is MainnetForkTestHelper {
uint256 vtAmount = 2000 ether;
address recipient = dave;
address treasury = validatorTicket.TREASURY();
address guardianModule = validatorTicket.GUARDIAN_MODULE();
address operationsMultisig = validatorTicket.OPERATIONS_MULTISIG();

uint256 vtPrice = IPufferOracle(address(validatorTicket.PUFFER_ORACLE())).getValidatorTicketPrice();
uint256 requiredETH = vtAmount.mulDiv(vtPrice, 1 ether, Math.Rounding.Ceil);
Expand All @@ -95,7 +96,7 @@ contract ValidatorTicketMainnetTest is MainnetForkTestHelper {
deal(address(validatorTicket.PUFFER_VAULT()), recipient, pufEthAmount);

uint256 initialTreasuryBalance = IERC20(validatorTicket.PUFFER_VAULT()).balanceOf(treasury);
uint256 initialGuardianBalance = IERC20(validatorTicket.PUFFER_VAULT()).balanceOf(guardianModule);
uint256 initialOperationsMultisigBalance = IERC20(validatorTicket.PUFFER_VAULT()).balanceOf(operationsMultisig);
uint256 initialBurnedAmount = IERC20(validatorTicket.PUFFER_VAULT()).totalSupply();

vm.startPrank(recipient);
Expand All @@ -115,9 +116,9 @@ contract ValidatorTicketMainnetTest is MainnetForkTestHelper {
"Treasury should receive 5% of pufETH"
);
assertEq(
IERC20(validatorTicket.PUFFER_VAULT()).balanceOf(guardianModule) - initialGuardianBalance,
IERC20(validatorTicket.PUFFER_VAULT()).balanceOf(operationsMultisig) - initialOperationsMultisigBalance,
expectedGuardianAmount,
"Guardians should receive 0.5% of pufETH"
"Operations Multisig should receive 0.5% of pufETH"
);
assertEq(
initialBurnedAmount - IERC20(validatorTicket.PUFFER_VAULT()).totalSupply(),
Expand Down
7 changes: 4 additions & 3 deletions mainnet-contracts/test/unit/ValidatorTicket.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ contract ValidatorTicketTest is UnitTestHelper {
uint256 vtAmount = 2000 ether; // Want to mint 2000 VTs
address recipient = actors[0];
address treasury = validatorTicket.TREASURY();
address operationsMultisig = validatorTicket.OPERATIONS_MULTISIG();

uint256 vtPrice = pufferOracle.getValidatorTicketPrice();
uint256 requiredETH = vtAmount.mulDiv(vtPrice, 1 ether, Math.Rounding.Ceil);
Expand All @@ -261,7 +262,7 @@ contract ValidatorTicketTest is UnitTestHelper {
_givePufETH(pufEthAmount, recipient);

uint256 initialTreasuryBalance = pufferVault.balanceOf(treasury);
uint256 initialGuardianBalance = pufferVault.balanceOf(address(guardianModule));
uint256 initialOpsMultisigBalance = pufferVault.balanceOf(operationsMultisig);
uint256 initialBurnedAmount = pufferVault.totalSupply();

vm.startPrank(recipient);
Expand All @@ -282,9 +283,9 @@ contract ValidatorTicketTest is UnitTestHelper {
"Treasury should receive 5% of pufETH"
);
assertEq(
pufferVault.balanceOf(address(guardianModule)) - initialGuardianBalance,
pufferVault.balanceOf(operationsMultisig) - initialOpsMultisigBalance,
expectedGuardianAmount,
"Guardians should receive 0.5% of pufETH"
"Operations Multisig should receive 0.5% of pufETH"
);
assertEq(
initialBurnedAmount - pufferVault.totalSupply(), expectedBurnAmount, "Remaining pufETH should be burned"
Expand Down
Loading