Skip to content

Commit

Permalink
feat: Add public view method getClaimableBondShares (#378)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergey Khomutinin <[email protected]>
  • Loading branch information
dgusakov and skhomuti authored Jan 13, 2025
1 parent 4a8d0c4 commit 28cc335
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/CSAccounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,13 @@ contract CSAccounting is
);
}

/// @inheritdoc ICSAccounting
function getClaimableBondShares(
uint256 nodeOperatorId
) public view returns (uint256) {
return _getClaimableBondShares(nodeOperatorId);
}

function _pullFeeRewards(
uint256 nodeOperatorId,
uint256 cumulativeFeeShares,
Expand Down
7 changes: 7 additions & 0 deletions src/interfaces/ICSAccounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ interface ICSAccounting is
uint256 nodeOperatorId
) external view returns (uint256 current, uint256 required);

/// @notice Get current claimable bond in stETH shares for the given Node Operator
/// @param nodeOperatorId ID of the Node Operator
/// @return Current claimable bond in stETH shares
function getClaimableBondShares(
uint256 nodeOperatorId
) external view returns (uint256);

/// @notice Unwrap the user's wstETH and deposit stETH to the bond for the given Node Operator
/// @dev Called by CSM exclusively
/// @param from Address to unwrap wstETH from
Expand Down
168 changes: 167 additions & 1 deletion test/CSAccounting.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2459,7 +2459,7 @@ contract CSAccountingClaimWstETHRewardsTest is
}
}

contract CSAccountingclaimRewardsUnstETHTest is
contract CSAccountingClaimRewardsUnstETHTest is
CSAccountingClaimRewardsBaseTest
{
function test_default() public override assertInvariants {
Expand Down Expand Up @@ -2870,6 +2870,172 @@ contract CSAccountingclaimRewardsUnstETHTest is
}
}

contract CSAccountingClaimableBondTest is CSAccountingRewardsBaseTest {
function test_default() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 32 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertEq(
claimableBondShares,
0,
"claimable bond shares should be zero"
);
}

function test_WithCurve() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 32 ether });
_rewards({ fee: 0.1 ether });
_curve(defaultCurve);

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertApproxEqAbs(
claimableBondShares,
stETH.getSharesByPooledEth(15 ether),
1 wei,
"claimable bond shares should be equal to the curve discount"
);
}

function test_WithLocked() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 33 ether });
_rewards({ fee: 0.1 ether });
_lock({ id: 0, amount: 1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertEq(
claimableBondShares,
0,
"claimable bond shares should be zero"
);
}

function test_WithCurveAndLocked() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 32 ether });
_rewards({ fee: 0.1 ether });
_curve(defaultCurve);
_lock({ id: 0, amount: 1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertApproxEqAbs(
claimableBondShares,
stETH.getSharesByPooledEth(14 ether),
1 wei,
"claimable bond shares should be equal to the curve discount minus locked"
);
}

function test_WithOneWithdrawnValidator() public override {
_operator({ ongoing: 16, withdrawn: 1 });
_deposit({ bond: 32 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertApproxEqAbs(
claimableBondShares,
stETH.getSharesByPooledEth(2 ether),
1 wei,
"claimable bond shares should be equal to a single validator bond"
);
}

function test_WithBond() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 32 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertEq(
claimableBondShares,
0,
"claimable bond shares should be zero"
);
}

function test_WithBondAndOneWithdrawnValidator() public override {
_operator({ ongoing: 16, withdrawn: 1 });
_deposit({ bond: 32 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertApproxEqAbs(
claimableBondShares,
stETH.getSharesByPooledEth(2 ether),
1 wei,
"claimable bond shares should be equal to a single validator bond"
);
}

function test_WithExcessBond() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 33 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertApproxEqAbs(
claimableBondShares,
stETH.getSharesByPooledEth(1 ether),
1 wei,
"claimable bond shares should be equal to the excess bond"
);
}

function test_WithExcessBondAndOneWithdrawnValidator() public override {
_operator({ ongoing: 16, withdrawn: 1 });
_deposit({ bond: 33 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertApproxEqAbs(
claimableBondShares,
stETH.getSharesByPooledEth(3 ether),
1 wei,
"claimable bond shares should be equal to a single validator bond plus the excess bond"
);
}

function test_WithMissingBond() public override {
_operator({ ongoing: 16, withdrawn: 0 });
_deposit({ bond: 16 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertEq(
claimableBondShares,
0,
"claimable bond shares should be zero"
);
}

function test_WithMissingBondAndOneWithdrawnValidator() public override {
_operator({ ongoing: 16, withdrawn: 1 });
_deposit({ bond: 16 ether });
_rewards({ fee: 0.1 ether });

uint256 claimableBondShares = accounting.getClaimableBondShares(0);

assertEq(
claimableBondShares,
0,
"claimable bond shares should be zero"
);
}
}

contract CSAccountingDepositEthTest is CSAccountingBaseTest {
function setUp() public override {
super.setUp();
Expand Down

0 comments on commit 28cc335

Please sign in to comment.