Skip to content

Commit

Permalink
feat: sync feat/vaults
Browse files Browse the repository at this point in the history
  • Loading branch information
loga4 committed Jan 16, 2025
2 parents 4d3f84d + 8cf3484 commit 73b10cc
Show file tree
Hide file tree
Showing 27 changed files with 893 additions and 477 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ SEPOLIA_RPC_URL=

# RPC URL for Hardhat Network forking, required for running tests on mainnet fork with tracing (Infura, Alchemy, etc.)
# https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#forking-other-networks
HARDHAT_FORKING_URL=
HARDHAT_FORKING_URL=https://eth.drpc.org

# Scratch deployment via hardhat variables
DEPLOYER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/tests-integration-mainnet.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Integration Tests

#on: [push]
#
#jobs:
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ mainnet environment, allowing you to run integration tests with trace logging.
> [!NOTE]
> Ensure that `HARDHAT_FORKING_URL` is set to Ethereum Mainnet RPC and `MAINNET_*` environment variables are set in the
> `.env` file (refer to `.env.example` for guidance).
> `.env` file (refer to `.env.example` for guidance). Otherwise, the tests will run against the Scratch deployment.
```bash
# Run all integration tests
Expand Down
17 changes: 16 additions & 1 deletion contracts/0.4.24/Lido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
* @param _eip712StETH eip712 helper contract for StETH
*/
function initialize(address _lidoLocator, address _eip712StETH) public payable onlyInit {
_bootstrapInitialHolder();
_bootstrapInitialHolder(); // stone in the elevator

LIDO_LOCATOR_POSITION.setStorageAddress(_lidoLocator);
emit LidoLocatorSet(_lidoLocator);
Expand Down Expand Up @@ -947,6 +947,21 @@ contract Lido is Versioned, StETHPermit, AragonApp {
return internalEther.add(_getExternalEther(internalEther));
}

/// @dev the numerator (in ether) of the share rate for StETH conversion between shares and ether and vice versa.
/// using the numerator and denominator different from totalShares and totalPooledEther allows to:
/// - avoid double precision loss on additional division on external ether calculations
/// - optimize gas cost of conversions between shares and ether
function _getShareRateNumerator() internal view returns (uint256) {
return _getInternalEther();
}

/// @dev the denominator (in shares) of the share rate for StETH conversion between shares and ether and vice versa.
function _getShareRateDenominator() internal view returns (uint256) {
uint256 externalShares = EXTERNAL_SHARES_POSITION.getStorageUint256();
uint256 internalShares = _getTotalShares() - externalShares; // never 0 because of the stone in the elevator
return internalShares;
}

/// @notice Calculate the maximum amount of external shares that can be minted while maintaining
/// maximum allowed external ratio limits
/// @return Maximum amount of external shares that can be minted
Expand Down
34 changes: 25 additions & 9 deletions contracts/0.4.24/StETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -303,17 +303,17 @@ contract StETH is IERC20, Pausable {
*/
function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) {
return _ethAmount
.mul(_getTotalShares())
.div(_getTotalPooledEther());
.mul(_getShareRateDenominator()) // denominator in shares
.div(_getShareRateNumerator()); // numerator in ether
}

/**
* @return the amount of ether that corresponds to `_sharesAmount` token shares.
*/
function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) {
return _sharesAmount
.mul(_getTotalPooledEther())
.div(_getTotalShares());
.mul(_getShareRateNumerator()) // numerator in ether
.div(_getShareRateDenominator()); // denominator in shares
}

/**
Expand All @@ -322,14 +322,14 @@ contract StETH is IERC20, Pausable {
* for `shareRate >= 0.5`, `getSharesByPooledEth(getPooledEthBySharesRoundUp(1))` will be 1.
*/
function getPooledEthBySharesRoundUp(uint256 _sharesAmount) public view returns (uint256 etherAmount) {
uint256 totalEther = _getTotalPooledEther();
uint256 totalShares = _getTotalShares();
uint256 numeratorInEther = _getShareRateNumerator();
uint256 denominatorInShares = _getShareRateDenominator();

etherAmount = _sharesAmount
.mul(totalEther)
.div(totalShares);
.mul(numeratorInEther)
.div(denominatorInShares);

if (etherAmount.mul(totalShares) != _sharesAmount.mul(totalEther)) {
if (_sharesAmount.mul(numeratorInEther) != etherAmount.mul(denominatorInShares)) {
++etherAmount;
}
}
Expand Down Expand Up @@ -389,6 +389,22 @@ contract StETH is IERC20, Pausable {
*/
function _getTotalPooledEther() internal view returns (uint256);

/**
* @return the numerator of the protocol's share rate (in ether).
* @dev used to convert shares to tokens and vice versa.
*/
function _getShareRateNumerator() internal view returns (uint256) {
return _getTotalPooledEther();
}

/**
* @return the denominator of the protocol's share rate (in shares).
* @dev used to convert shares to tokens and vice versa.
*/
function _getShareRateDenominator() internal view returns (uint256) {
return _getTotalShares();
}

/**
* @notice Moves `_amount` tokens from `_sender` to `_recipient`.
* Emits a `Transfer` event.
Expand Down
51 changes: 51 additions & 0 deletions contracts/0.8.25/utils/PausableUntilWithRoles.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

// See contracts/COMPILERS.md
pragma solidity 0.8.25;

import {PausableUntil} from "contracts/common/utils/PausableUntil.sol";
import {AccessControlEnumerableUpgradeable} from "contracts/openzeppelin/5.0.2/upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";

/**
* @title PausableUntilWithRoles
* @notice a `PausableUntil` implementation using OpenZeppelin's `AccessControlEnumerableUpgradeable`
* @dev the inheriting contract must use `whenNotPaused` modifier from `PausableUntil` to block some functions on pause
*/
abstract contract PausableUntilWithRoles is PausableUntil, AccessControlEnumerableUpgradeable {
/// @notice role that allows to pause the contract
bytes32 public constant PAUSE_ROLE = keccak256("PausableUntilWithRoles.PauseRole");
/// @notice role that allows to resume the contract
bytes32 public constant RESUME_ROLE = keccak256("PausableUntilWithRoles.ResumeRole");

/**
* @notice Resume the contract
* @dev Reverts if contracts is not paused
* @dev Reverts if sender has no `RESUME_ROLE`
*/
function resume() external onlyRole(RESUME_ROLE) {
_resume();
}

/**
* @notice Pause the contract for a specified period
* @param _duration pause duration in seconds (use `PAUSE_INFINITELY` for unlimited)
* @dev Reverts if contract is already paused
* @dev Reverts if sender has no `PAUSE_ROLE`
* @dev Reverts if zero duration is passed
*/
function pauseFor(uint256 _duration) external onlyRole(PAUSE_ROLE) {
_pauseFor(_duration);
}

/**
* @notice Pause the contract until a specified timestamp
* @param _pauseUntilInclusive the last second to pause until inclusive
* @dev Reverts if the timestamp is in the past
* @dev Reverts if sender has no `PAUSE_ROLE`
* @dev Reverts if contract is already paused
*/
function pauseUntil(uint256 _pauseUntilInclusive) external onlyRole(PAUSE_ROLE) {
_pauseUntil(_pauseUntilInclusive);
}
}
Loading

0 comments on commit 73b10cc

Please sign in to comment.