Skip to content

Commit

Permalink
feat: Use REQUEST_BURN_MY_STETH_ROLE role (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgusakov authored Jan 14, 2025
1 parent 9f812b3 commit b338668
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 40 deletions.
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);
}
}

0 comments on commit b338668

Please sign in to comment.