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

feat: Use REQUEST_BURN_MY_STETH_ROLE role #381

Merged
merged 3 commits into from
Jan 14, 2025
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
1 change: 1 addition & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ test-local *args:
@while ! echo exit | nc {{anvil_host}} {{anvil_port}} > /dev/null; do sleep 1; done
DEPLOYER_PRIVATE_KEY=`cat localhost.json | jq -r ".private_keys[0]"` \
just deploy --silent

DEPLOY_CONFIG=./artifacts/local/deploy-{{chain}}.json \
RPC_URL={{anvil_rpc_url}} \
just test-deployment {{args}}
Expand Down
13 changes: 12 additions & 1 deletion script/fork-helpers/SimulateVote.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CSModule } from "../../src/CSModule.sol";
import { CSAccounting } from "../../src/CSAccounting.sol";
import { CSFeeOracle } from "../../src/CSFeeOracle.sol";
import { IBurner } from "../../src/interfaces/IBurner.sol";
import { ILidoLocator } from "../../src/interfaces/ILidoLocator.sol";
import { ForkHelpersCommon } from "./Common.sol";

contract SimulateVote is Script, DeploymentFixtures, ForkHelpersCommon {
Expand Down Expand Up @@ -53,7 +54,7 @@ contract SimulateVote is Script, DeploymentFixtures, ForkHelpersCommon {
});
// 2. burner role
burner.grantRole(
burner.REQUEST_BURN_SHARES_ROLE(),
burner.REQUEST_BURN_MY_STETH_ROLE(),
address(accounting)
);
// 3. Grant resume to agent
Expand Down Expand Up @@ -101,9 +102,11 @@ contract SimulateVote is Script, DeploymentFixtures, ForkHelpersCommon {
feeDistributorProxy.proxy__upgradeTo(upgradeConfig.feeDistributorImpl);

address admin = _prepareAdmin(deploymentConfig.csm);
locator = ILidoLocator(deploymentConfig.lidoLocator);
csm = CSModule(deploymentConfig.csm);
accounting = CSAccounting(deploymentConfig.accounting);
oracle = CSFeeOracle(deploymentConfig.oracle);
IBurner burner = IBurner(locator.burner());

vm.startBroadcast(admin);
csm.revokeRole(csm.VERIFIER_ROLE(), address(deploymentConfig.verifier));
Expand All @@ -125,6 +128,14 @@ contract SimulateVote is Script, DeploymentFixtures, ForkHelpersCommon {
address(upgradeConfig.gateSeal)
);
oracle.grantRole(oracle.PAUSE_ROLE(), address(upgradeConfig.gateSeal));
burner.revokeRole(
burner.REQUEST_BURN_SHARES_ROLE(),
address(accounting)
);
burner.grantRole(
burner.REQUEST_BURN_MY_STETH_ROLE(),
address(accounting)
);
vm.stopBroadcast();
}
}
10 changes: 4 additions & 6 deletions src/abstract/CSBondCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -179,22 +179,20 @@ abstract contract CSBondCore is ICSBondCore {
}

/// @dev Burn Node Operator's bond shares (stETH). Shares will be burned on the next stETH rebase
/// @dev The method sender should be granted as `Burner.REQUEST_BURN_SHARES_ROLE` and make stETH allowance for `Burner`
/// @dev The method sender should be granted as `Burner.REQUEST_BURN_MY_STETH_ROLE` and make stETH allowance for `Burner`
/// @param amount Bond amount to burn in ETH (stETH)
function _burn(uint256 nodeOperatorId, uint256 amount) internal {
uint256 toBurnShares = _sharesByEth(amount);
uint256 burnedShares = _reduceBond(nodeOperatorId, toBurnShares);
// If no bond already
if (burnedShares == 0) return;
uint256 burnedAmount = _ethByShares(burnedShares);

IBurner(LIDO_LOCATOR.burner()).requestBurnShares(
address(this),
burnedShares
);
IBurner(LIDO_LOCATOR.burner()).requestBurnMyStETH(burnedAmount);
emit BondBurned(
nodeOperatorId,
_ethByShares(toBurnShares),
_ethByShares(burnedShares)
burnedAmount
);
}

Expand Down
9 changes: 5 additions & 4 deletions src/interfaces/IBurner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
pragma solidity 0.8.24;

interface IBurner {
function REQUEST_BURN_MY_STETH_ROLE() external view returns (bytes32);

function REQUEST_BURN_SHARES_ROLE() external view returns (bytes32);

function DEFAULT_ADMIN_ROLE() external view returns (bytes32);
Expand All @@ -15,13 +17,12 @@ interface IBurner {

function grantRole(bytes32 role, address account) external;

function revokeRole(bytes32 role, address account) external;

function hasRole(
bytes32 role,
address account
) external view returns (bool);

function requestBurnShares(
address _from,
uint256 _sharesAmountToBurn
) external;
function requestBurnMyStETH(uint256 _stETHAmountToBurn) external;
}
8 changes: 4 additions & 4 deletions test/CSAccounting.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3708,13 +3708,13 @@ contract CSAccountingPenalizeTest is CSAccountingBaseTest {
function test_penalize() public assertInvariants {
uint256 shares = stETH.getSharesByPooledEth(1 ether);
uint256 bondSharesBefore = accounting.getBondShares(0);
uint256 amountToBurn = stETH.getPooledEthByShares(shares);

vm.expectCall(
locator.burner(),
abi.encodeWithSelector(
IBurner.requestBurnShares.selector,
address(accounting),
shares
IBurner.requestBurnMyStETH.selector,
amountToBurn
)
);

Expand Down Expand Up @@ -3919,7 +3919,7 @@ contract CSAccountingLockBondETHTest is CSAccountingBaseTest {

expectNoCall(
address(burner),
abi.encodeWithSelector(IBurner.requestBurnShares.selector)
abi.encodeWithSelector(IBurner.requestBurnMyStETH.selector)
);
accounting.settleLockedBondETH(noId);
vm.stopPrank();
Expand Down
19 changes: 6 additions & 13 deletions test/CSBondCore.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -491,11 +491,7 @@ contract CSBondCoreBurnTest is CSBondCoreTestBase {
uint256 bondSharesBefore = bondCore.getBondShares(0);
vm.expectCall(
locator.burner(),
abi.encodeWithSelector(
IBurner.requestBurnShares.selector,
address(bondCore),
shares
)
abi.encodeWithSelector(IBurner.requestBurnMyStETH.selector, burned)
);
bondCore.burn(0, 1 ether);
uint256 bondSharesAfter = bondCore.getBondShares(0);
Expand All @@ -513,6 +509,8 @@ contract CSBondCoreBurnTest is CSBondCoreTestBase {

uint256 bondSharesBefore = bondCore.getBondShares(0);
uint256 burnShares = stETH.getSharesByPooledEth(33 ether);
uint256 sharesToBurn = stETH.getSharesByPooledEth(32 ether);
uint256 amountToBurn = stETH.getPooledEthByShares(sharesToBurn);
vm.expectEmit(true, true, true, true, address(bondCore));
emit ICSBondCore.BondBurned(
0,
Expand All @@ -523,9 +521,8 @@ contract CSBondCoreBurnTest is CSBondCoreTestBase {
vm.expectCall(
locator.burner(),
abi.encodeWithSelector(
IBurner.requestBurnShares.selector,
address(bondCore),
stETH.getSharesByPooledEth(32 ether)
IBurner.requestBurnMyStETH.selector,
amountToBurn
)
);

Expand All @@ -549,11 +546,7 @@ contract CSBondCoreBurnTest is CSBondCoreTestBase {

vm.expectCall(
locator.burner(),
abi.encodeWithSelector(
IBurner.requestBurnShares.selector,
address(bondCore),
shares
)
abi.encodeWithSelector(IBurner.requestBurnMyStETH.selector, burned)
);

bondCore.burn(0, 32 ether);
Expand Down
4 changes: 2 additions & 2 deletions test/fork/integration/Penalty.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,13 @@ contract PenaltyIntegrationTest is
IBurner burner = IBurner(locator.burner());
if (
!burner.hasRole(
burner.REQUEST_BURN_SHARES_ROLE(),
burner.REQUEST_BURN_MY_STETH_ROLE(),
address(accounting)
)
) {
vm.startPrank(burner.getRoleMember(burner.DEFAULT_ADMIN_ROLE(), 0));
burner.grantRole(
burner.REQUEST_BURN_SHARES_ROLE(),
burner.REQUEST_BURN_MY_STETH_ROLE(),
address(accounting)
);
vm.stopPrank();
Expand Down
6 changes: 6 additions & 0 deletions test/fork/voting/StatePostVote.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ contract ContractsStateTest is Test, Utilities, DeploymentFixtures {
accounting.getCurveInfo(earlyAdoption.CURVE_ID()).points,
deployParams.earlyAdoptionBondCurve
);
assertTrue(
burner.hasRole(
burner.REQUEST_BURN_MY_STETH_ROLE(),
address(accounting)
)
);
}

function test_accountingRoles() public {
Expand Down
3 changes: 3 additions & 0 deletions test/helpers/Fixtures.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Stub } from "./mocks/Stub.sol";
import "forge-std/Test.sol";
import { IStakingRouter } from "../../src/interfaces/IStakingRouter.sol";
import { ILido } from "../../src/interfaces/ILido.sol";
import { IBurner } from "../../src/interfaces/IBurner.sol";
import { ILidoLocator } from "../../src/interfaces/ILidoLocator.sol";
import { IWstETH } from "../../src/interfaces/IWstETH.sol";
import { IGateSeal } from "../../src/interfaces/IGateSeal.sol";
Expand Down Expand Up @@ -224,6 +225,7 @@ contract DeploymentFixtures is StdCheats, DeploymentHelpers {
IStakingRouter public stakingRouter;
ILido public lido;
IGateSeal public gateSeal;
IBurner public burner;

function initializeFromDeployment() public {
Env memory env = envVars();
Expand All @@ -245,6 +247,7 @@ contract DeploymentFixtures is StdCheats, DeploymentHelpers {
stakingRouter = IStakingRouter(locator.stakingRouter());
wstETH = IWstETH(IWithdrawalQueue(locator.withdrawalQueue()).WSTETH());
gateSeal = IGateSeal(deploymentConfig.gateSeal);
burner = IBurner(locator.burner());

if (!_isEmpty(env.UPGRADE_CONFIG)) {
UpgradeConfig memory upgradeConfig = parseUpgradeConfig(
Expand Down
13 changes: 3 additions & 10 deletions test/helpers/mocks/BurnerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,8 @@ contract BurnerMock {
STETH = _stETH;
}

function requestBurnShares(
address _from,
uint256 _sharesAmountToBurn
) external {
IStETH(STETH).transferSharesFrom(
_from,
address(this),
_sharesAmountToBurn
);
if (_sharesAmountToBurn == 0) revert ZeroBurnAmount();
function requestBurnMyStETH(uint256 _amountToBurn) external {
if (_amountToBurn == 0) revert ZeroBurnAmount();
IStETH(STETH).transferFrom(msg.sender, address(this), _amountToBurn);
}
}
Loading