Skip to content

Commit

Permalink
chore: update naming and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tamtamchik committed Dec 3, 2024
1 parent 28fedbd commit 6f9b89d
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 28 deletions.
10 changes: 5 additions & 5 deletions contracts/0.4.24/Lido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,8 @@ contract Lido is Versioned, StETHPermit, AragonApp {

/// @notice Get the maximum additional stETH amount that can be added to external balance without exceeding limits
/// @return Maximum stETH amount that can be added to external balance
function getMaxExternalEtherAmount() external view returns (uint256) {
return _getMaxExternalEtherAmount();
function getMaxAvailableExternalBalance() external view returns (uint256) {
return _getMaxAvailableExternalBalance();
}

/**
Expand Down Expand Up @@ -928,7 +928,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
/// Formula: x <= (maxBP * totalPooled - currentExternal * TOTAL_BP) / (TOTAL_BP - maxBP).
/// Returns 0 if maxBP is 0 or if current external balance already exceeds limit.
/// Returns uint256.max if maxBP >= TOTAL_BASIS_POINTS.
function _getMaxAdditionalExternalEther() internal view returns (uint256) {
function _getMaxAvailableExternalBalance() internal view returns (uint256) {
uint256 maxBP = MAX_EXTERNAL_BALANCE_POSITION.getStorageUint256();
uint256 externalBalance = EXTERNAL_BALANCE_POSITION.getStorageUint256();
uint256 totalPooledEther = _getTotalPooledEther();
Expand All @@ -946,10 +946,10 @@ contract Lido is Versioned, StETHPermit, AragonApp {
/// @param _stethAmount The amount of stETH being added to external balance
/// @return The new total external balance after adding _stethAmount
/// @dev Validates that the new external balance would not exceed the maximum allowed amount
/// by comparing with _getMaxPossibleExternalAmount
/// by comparing with _getMaxAvailableExternalBalance
function _getNewExternalBalance(uint256 _stethAmount) internal view returns (uint256) {
uint256 currentExternal = EXTERNAL_BALANCE_POSITION.getStorageUint256();
uint256 maxAmountToAdd = _getMaxAdditionalExternalEther();
uint256 maxAmountToAdd = _getMaxAvailableExternalBalance();

require(_stethAmount <= maxAmountToAdd, "EXTERNAL_BALANCE_LIMIT_EXCEEDED");

Expand Down
2 changes: 1 addition & 1 deletion contracts/0.8.25/interfaces/ILido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ILido {

function burnExternalShares(uint256) external;

function getMaxExternalEther() external view returns (uint256);
function getMaxAvailableExternalBalance() external view returns (uint256);

function getTotalShares() external view returns (uint256);

Expand Down
8 changes: 4 additions & 4 deletions contracts/0.8.25/vaults/VaultHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable {
}

uint256 capVaultBalance = stETH.getPooledEthByShares(_shareLimit);
uint256 maxExternalBalance = stETH.getMaxExternalEther();
if (capVaultBalance + stETH.getExternalEther() > maxExternalBalance) {
revert ExternalBalanceCapReached(address(_vault), capVaultBalance, maxExternalBalance);
uint256 maxAvailableExternalBalance = stETH.getMaxAvailableExternalBalance();
if (capVaultBalance > maxAvailableExternalBalance) {
revert ExternalBalanceCapReached(address(_vault), capVaultBalance, maxAvailableExternalBalance);
}

VaultSocket memory vr = VaultSocket(
Expand Down Expand Up @@ -480,7 +480,7 @@ abstract contract VaultHub is AccessControlEnumerableUpgradeable {
error ShareLimitTooHigh(address vault, uint256 capShares, uint256 maxCapShares);
error ReserveRatioTooHigh(address vault, uint256 reserveRatioBP, uint256 maxReserveRatioBP);
error TreasuryFeeTooHigh(address vault, uint256 treasuryFeeBP, uint256 maxTreasuryFeeBP);
error ExternalBalanceCapReached(address vault, uint256 capVaultBalance, uint256 maxExternalBalance);
error ExternalBalanceCapReached(address vault, uint256 capVaultBalance, uint256 maxAvailableExternalBalance);
error InsufficientValuationToMint(address vault, uint256 valuation);
error AlreadyExists(address addr);
error FactoryNotAllowed(address beacon);
Expand Down
47 changes: 30 additions & 17 deletions test/0.4.24/lido/lido.externalBalance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe("Lido.sol:externalBalance", () => {

context("getMaxExternalBalanceBP", () => {
it("should return the correct value", async () => {
expect(await lido.getMaxExternalBalanceBP()).to.be.equal(0n);
expect(await lido.getMaxExternalBalanceBP()).to.equal(0n);
});
});

Expand All @@ -76,7 +76,7 @@ describe("Lido.sol:externalBalance", () => {
.to.emit(lido, "MaxExternalBalanceBPSet")
.withArgs(newMaxExternalBalanceBP);

expect(await lido.getMaxExternalBalanceBP()).to.be.equal(newMaxExternalBalanceBP);
expect(await lido.getMaxExternalBalanceBP()).to.equal(newMaxExternalBalanceBP);
});
});

Expand All @@ -85,42 +85,55 @@ describe("Lido.sol:externalBalance", () => {
await lido.setMaxExternalBalanceBP(maxExternalBalanceBP);

// Add some external ether to protocol
const amountToMint = (await lido.getMaxExternalEther()) - 1n;
const amountToMint = (await lido.getMaxAvailableExternalBalance()) - 1n;
const accountingSigner = await impersonate(await locator.accounting(), ether("1"));
await lido.connect(accountingSigner).mintExternalShares(whale, amountToMint);

expect(await lido.getExternalEther()).to.be.equal(amountToMint);
expect(await lido.getExternalEther()).to.equal(amountToMint);
});
});

context("getMaxExternalEther", () => {
context("getMaxAvailableExternalBalance", () => {
beforeEach(async () => {
// Increase the external ether limit to 10%
await lido.setMaxExternalBalanceBP(maxExternalBalanceBP);
});

it("returns the correct value", async () => {
const totalEther = (await lido.getTotalPooledEther()) - (await lido.getExternalEther());
/**
* Calculates the maximum additional stETH that can be added to external balance without exceeding limits
*
* Invariant: (currentExternal + x) / (totalPooled + x) <= maxBP / TOTAL_BP
* Formula: x <= (maxBP * totalPooled - currentExternal * TOTAL_BP) / (TOTAL_BP - maxBP)
*/
async function getExpectedMaxAvailableExternalBalance() {
const totalPooledEther = await lido.getTotalPooledEther();
const externalEther = await lido.getExternalEther();

return (
(maxExternalBalanceBP * totalPooledEther - externalEther * TOTAL_BASIS_POINTS) /
(TOTAL_BASIS_POINTS - maxExternalBalanceBP)
);
}

const expectedMaxExternalEther = (totalEther * maxExternalBalanceBP) / TOTAL_BASIS_POINTS;
it("returns the correct value", async () => {
const expectedMaxExternalEther = await getExpectedMaxAvailableExternalBalance();

expect(await lido.getMaxExternalEther()).to.be.equal(expectedMaxExternalEther);
expect(await lido.getMaxAvailableExternalBalance()).to.equal(expectedMaxExternalEther);
});

it("holds when external ether value changes", async () => {
const totalEtherBefore = (await lido.getTotalPooledEther()) - (await lido.getExternalEther());
const expectedMaxExternalEtherBefore = (totalEtherBefore * maxExternalBalanceBP) / TOTAL_BASIS_POINTS;
const expectedMaxExternalEtherBefore = await getExpectedMaxAvailableExternalBalance();

// Add some external ether to protocol
const amountToMint = (await lido.getMaxExternalEther()) - 1n;
expect(await lido.getMaxAvailableExternalBalance()).to.equal(expectedMaxExternalEtherBefore);

// Add all available external ether to protocol
const amountToMint = await lido.getMaxAvailableExternalBalance();
const accountingSigner = await impersonate(await locator.accounting(), ether("1"));
await lido.connect(accountingSigner).mintExternalShares(whale, amountToMint);

const totalEtherAfter = (await lido.getTotalPooledEther()) - (await lido.getExternalEther());
const expectedMaxExternalEtherAfter = (totalEtherAfter * maxExternalBalanceBP) / TOTAL_BASIS_POINTS;
const expectedMaxExternalEtherAfter = await getExpectedMaxAvailableExternalBalance();

expect(expectedMaxExternalEtherBefore).to.be.equal(expectedMaxExternalEtherAfter);
expect(await lido.getMaxExternalEther()).to.be.equal(expectedMaxExternalEtherAfter);
expect(expectedMaxExternalEtherAfter).to.equal(0n);
});
});
});
3 changes: 2 additions & 1 deletion test/0.8.25/vaults/contracts/StETH__HarnessForVaultHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ contract StETH__HarnessForVaultHub is StETH {
return externalBalance;
}

function getMaxExternalEther() external view returns (uint256) {
// This is simplified version of the function for testing purposes
function getMaxAvailableExternalBalance() external view returns (uint256) {
return _getTotalPooledEther().mul(maxExternalBalanceBp).div(TOTAL_BASIS_POINTS);
}

Expand Down

0 comments on commit 6f9b89d

Please sign in to comment.