Skip to content

Commit

Permalink
Merge pull request #709 from lidofinance/fix/shapella-upgrade-from-rc…
Browse files Browse the repository at this point in the history
…0-to-rc1

Feat: shapella upgrade from rc.0 to rc.1 [WIP]
  • Loading branch information
TheDZhon authored Apr 4, 2023
2 parents 73eccd7 + 3c4bb28 commit feafec4
Show file tree
Hide file tree
Showing 118 changed files with 2,245 additions and 1,002 deletions.
52 changes: 0 additions & 52 deletions .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,55 +95,3 @@ jobs:
- name: Run Solidity test coverage
run: yarn test:coverage
continue-on-error: false

abi-lint:
name: ABI actuality linter
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
persist-credentials: false

- name: Setup node.js version
uses: actions/setup-node@v3
with:
node-version: 16

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT

- name: Cache yarn cache
id: cache-yarn-cache
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: yarn-${{ hashFiles('**/yarn.lock') }}

- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: node_modules-${{ hashFiles('**/yarn.lock') }}

- name: Install modules
run: yarn
if: |
steps.cache-yarn-cache.outputs.cache-hit != 'true' ||
steps.cache-node-modules.outputs.cache-hit != 'true'
- name: Compile code and extract ABI
run: yarn compile

- name: Check for ABI changes
run: |
git diff --quiet lib/abi && status=clean || status=dirty
if [ $status == "dirty" ]; then
echo "The following ABIs should be commited"
git diff --compact-summary lib/abi
exit 1
fi
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.vscode
**/build/
**/node_modules/
**/lib/abi/*.json
**/artifacts/
**/artifacts-userdoc/
.cache
Expand Down
2 changes: 0 additions & 2 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@ RED_COLOR='\033[0;31m'
NO_COLOR='\033[0m'

yarn compile
git diff --quiet lib/abi || (echo -e "${RED_COLOR}Unstaged ABIs detected${NO_COLOR}"; exit 1)

yarn lint
82 changes: 58 additions & 24 deletions contracts/0.4.24/Lido.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ interface IStakingRouter {
external
view
returns (uint256);

function TOTAL_BASIS_POINTS() external view returns (uint256);
}

interface IWithdrawalQueue {
Expand Down Expand Up @@ -266,11 +268,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
payable
onlyInit
{
uint256 amount = _bootstrapInitialHolder();
_setBufferedEther(amount);

emit Submitted(INITIAL_TOKEN_HOLDER, amount, 0);

_bootstrapInitialHolder();
_initialize_v2(_lidoLocator, _eip712StETH);
initialized();
}
Expand Down Expand Up @@ -340,6 +338,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
*/
function resumeStaking() external {
_auth(STAKING_CONTROL_ROLE);
require(hasInitialized(), "NOT_INITIALIZED");

_resumeStaking();
}
Expand Down Expand Up @@ -673,7 +672,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
* Depends on the bunker state and protocol's pause state
*/
function canDeposit() public view returns (bool) {
return !IWithdrawalQueue(getLidoLocator().withdrawalQueue()).isBunkerModeActive() && !isStopped();
return !_withdrawalQueue().isBunkerModeActive() && !isStopped();
}

/**
Expand All @@ -682,7 +681,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
*/
function getDepositableEther() public view returns (uint256) {
uint256 bufferedEther = _getBufferedEther();
uint256 withdrawalReserve = IWithdrawalQueue(getLidoLocator().withdrawalQueue()).unfinalizedStETH();
uint256 withdrawalReserve = _withdrawalQueue().unfinalizedStETH();
return bufferedEther > withdrawalReserve ? bufferedEther - withdrawalReserve : 0;
}

Expand All @@ -698,7 +697,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
require(msg.sender == locator.depositSecurityModule(), "APP_AUTH_DSM_FAILED");
require(canDeposit(), "CAN_NOT_DEPOSIT");

IStakingRouter stakingRouter = IStakingRouter(locator.stakingRouter());
IStakingRouter stakingRouter = _stakingRouter();
uint256 depositsCount = Math256.min(
_maxDepositsCount,
stakingRouter.getStakingModuleMaxDepositsCount(_stakingModuleId, getDepositableEther())
Expand Down Expand Up @@ -730,7 +729,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
* @dev DEPRECATED: use StakingRouter.getWithdrawalCredentials() instead
*/
function getWithdrawalCredentials() external view returns (bytes32) {
return IStakingRouter(getLidoLocator().stakingRouter()).getWithdrawalCredentials();
return _stakingRouter().getWithdrawalCredentials();
}

/**
Expand All @@ -746,7 +745,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
* @dev DEPRECATED: use LidoLocator.treasury()
*/
function getTreasury() external view returns (address) {
return getLidoLocator().treasury();
return _treasury();
}

/**
Expand All @@ -757,11 +756,11 @@ contract Lido is Versioned, StETHPermit, AragonApp {
* inaccurate because the actual value is truncated here to 1e4 precision.
*/
function getFee() external view returns (uint16 totalFee) {
totalFee = IStakingRouter(getLidoLocator().stakingRouter()).getTotalFeeE4Precision();
totalFee = _stakingRouter().getTotalFeeE4Precision();
}

/**
* @notice Returns current fee distribution
* @notice Returns current fee distribution, values relative to the total fee (getFee())
* @dev DEPRECATED: Now fees information is stored in StakingRouter and
* with higher precision. Use StakingRouter.getStakingFeeAggregateDistribution() instead.
* @return treasuryFeeBasisPoints return treasury fee in TOTAL_BASIS_POINTS (10000 is 100% fee) precision
Expand All @@ -780,9 +779,15 @@ contract Lido is Versioned, StETHPermit, AragonApp {
uint16 operatorsFeeBasisPoints
)
{
insuranceFeeBasisPoints = 0; // explicitly set to zero
(treasuryFeeBasisPoints, operatorsFeeBasisPoints) = IStakingRouter(getLidoLocator().stakingRouter())
IStakingRouter stakingRouter = _stakingRouter();
uint256 totalBasisPoints = stakingRouter.TOTAL_BASIS_POINTS();
uint256 totalFee = stakingRouter.getTotalFeeE4Precision();
(uint256 treasuryFeeBasisPointsAbs, uint256 operatorsFeeBasisPointsAbs) = stakingRouter
.getStakingFeeAggregateDistributionE4Precision();

insuranceFeeBasisPoints = 0; // explicitly set to zero
treasuryFeeBasisPoints = uint16((treasuryFeeBasisPointsAbs * totalBasisPoints) / totalFee);
operatorsFeeBasisPoints = uint16((operatorsFeeBasisPointsAbs * totalBasisPoints) / totalFee);
}

/*
Expand Down Expand Up @@ -941,14 +946,6 @@ contract Lido is Versioned, StETHPermit, AragonApp {
return sharesAmount;
}

/**
* @dev Emits {Transfer} and {TransferShares} events where `from` is 0 address. Indicates mint events.
*/
function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal {
emit Transfer(address(0), _to, getPooledEthByShares(_sharesAmount));
emit TransferShares(address(0), _to, _sharesAmount);
}

/**
* @dev Staking router rewards distribution.
*
Expand All @@ -970,7 +967,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
StakingRewardsDistribution memory ret,
IStakingRouter router
) {
router = IStakingRouter(getLidoLocator().stakingRouter());
router = _stakingRouter();

(
ret.recipients,
Expand Down Expand Up @@ -1075,7 +1072,7 @@ contract Lido is Versioned, StETHPermit, AragonApp {
}

function _transferTreasuryRewards(uint256 treasuryReward) internal {
address treasury = getLidoLocator().treasury();
address treasury = _treasury();
_transferShares(address(this), treasury, treasuryReward);
_emitTransferAfterMintingShares(treasury, treasuryReward);
}
Expand Down Expand Up @@ -1371,4 +1368,41 @@ contract Lido is Versioned, StETHPermit, AragonApp {
ret.postTokenRebaseReceiver
) = getLidoLocator().oracleReportComponentsForLido();
}

function _stakingRouter() internal view returns (IStakingRouter) {
return IStakingRouter(getLidoLocator().stakingRouter());
}

function _withdrawalQueue() internal view returns (IWithdrawalQueue) {
return IWithdrawalQueue(getLidoLocator().withdrawalQueue());
}

function _treasury() internal view returns (address) {
return getLidoLocator().treasury();
}

/**
* @notice Mints shares on behalf of 0xdead address,
* the shares amount is equal to the contract's balance. *
*
* Allows to get rid of zero checks for `totalShares` and `totalPooledEther`
* and overcome corner cases.
*
* NB: reverts if the current contract's balance is zero.
*
* @dev must be invoked before using the token
*/
function _bootstrapInitialHolder() internal {
uint256 balance = address(this).balance;
assert(balance != 0);

if (_getTotalShares() == 0) {
// if protocol is empty bootstrap it with the contract's balance
// address(0xdead) is a holder for initial shares
_setBufferedEther(balance);
// emitting `Submitted` before Transfer events to preserver events order in tx
emit Submitted(INITIAL_TOKEN_HOLDER, balance, 0);
_mintInitialShares(balance);
}
}
}
49 changes: 20 additions & 29 deletions contracts/0.4.24/StETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,8 @@ contract StETH is IERC20, Pausable {
*/
function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256) {
_transferShares(msg.sender, _recipient, _sharesAmount);
emit TransferShares(msg.sender, _recipient, _sharesAmount);
uint256 tokensAmount = getPooledEthByShares(_sharesAmount);
emit Transfer(msg.sender, _recipient, tokensAmount);
_emitTransferEvents(msg.sender, _recipient, tokensAmount, _sharesAmount);
return tokensAmount;
}

Expand Down Expand Up @@ -362,8 +361,7 @@ contract StETH is IERC20, Pausable {

_transferShares(_sender, _recipient, _sharesAmount);
_approve(_sender, msg.sender, currentAllowance.sub(tokensAmount));
emit TransferShares(_sender, _recipient, _sharesAmount);
emit Transfer(_sender, _recipient, tokensAmount);
_emitTransferEvents(_sender, _recipient, tokensAmount, _sharesAmount);
return tokensAmount;
}

Expand All @@ -382,8 +380,7 @@ contract StETH is IERC20, Pausable {
function _transfer(address _sender, address _recipient, uint256 _amount) internal {
uint256 _sharesToTransfer = getSharesByPooledEth(_amount);
_transferShares(_sender, _recipient, _sharesToTransfer);
emit Transfer(_sender, _recipient, _amount);
emit TransferShares(_sender, _recipient, _sharesToTransfer);
_emitTransferEvents(_sender, _recipient, _amount, _sharesToTransfer);
}

/**
Expand Down Expand Up @@ -507,31 +504,25 @@ contract StETH is IERC20, Pausable {
}

/**
* @notice Mints shares on behalf of 0xdead address,
* the shares amount is equal to the contract's balance. *
*
* Allows to get rid of zero checks for `totalShares` and `totalPooledEther`
* and overcome corner cases.
*
* NB: reverts if the current contract's balance is zero.
*
* @dev must be invoked before using the token
* @dev Emits {Transfer} and {TransferShares} events
*/
function _bootstrapInitialHolder() internal returns (uint256) {
uint256 balance = address(this).balance;
assert(balance != 0);

if (_getTotalShares() == 0) {
// if protocol is empty bootstrap it with the contract's balance
// address(0xdead) is a holder for initial shares
_mintShares(INITIAL_TOKEN_HOLDER, balance);

emit Transfer(0x0, INITIAL_TOKEN_HOLDER, balance);
emit TransferShares(0x0, INITIAL_TOKEN_HOLDER, balance);
function _emitTransferEvents(address _from, address _to, uint _tokenAmount, uint256 _sharesAmount) internal {
emit Transfer(_from, _to, _tokenAmount);
emit TransferShares(_from, _to, _sharesAmount);
}

return balance;
}
/**
* @dev Emits {Transfer} and {TransferShares} events where `from` is 0 address. Indicates mint events.
*/
function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal {
_emitTransferEvents(address(0), _to, getPooledEthByShares(_sharesAmount), _sharesAmount);
}

return 0;
/**
* @dev Mints shares to INITIAL_TOKEN_HOLDER
*/
function _mintInitialShares(uint256 _sharesAmount) internal {
_mintShares(INITIAL_TOKEN_HOLDER, _sharesAmount);
_emitTransferAfterMintingShares(INITIAL_TOKEN_HOLDER, _sharesAmount);
}
}
35 changes: 26 additions & 9 deletions contracts/0.4.24/lib/Packed64x4.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,43 @@
// solhint-disable-next-line
pragma solidity ^0.4.24;

import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol";

/// @notice Provides an interface for gas-efficient operations on four uint64 type
/// variables tightly packed into one uint256 variable stored in memory
library Packed64x4 {
using SafeMath for uint256;
using Packed64x4 for Packed64x4.Packed;

// string private constant ERROR_OFFSET_OUT_OF_RANGE = "OFFSET_OUT_OF_RANGE";
uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF;

struct Packed {
uint256 v;
}

//extract n-th uint64 from uint256
function get(Packed memory _self, uint8 n) internal pure returns (uint64 r) {
// require(n < 4, ERROR_OFFSET_OUT_OF_RANGE);
r = uint64((_self.v >> (64 * n)) & UINT64_MAX);
/// @dev Returns uint64 variable stored on position `n` as uint256
function get(Packed memory _self, uint8 n) internal pure returns (uint256 r) {
r = (_self.v >> (64 * n)) & UINT64_MAX;
}

//merge n-th uint64 to uint256
function set(Packed memory _self, uint8 n, uint64 x) internal pure {
// require(n < 4, ERROR_OFFSET_OUT_OF_RANGE);
_self.v = _self.v & ~(UINT64_MAX << (64 * n)) | ((uint256(x) & UINT64_MAX) << (64 * n));
/// @dev Writes value stored in passed `x` variable on position `n`.
/// The passed value must be less or equal to UINT64_MAX.
/// If the passed value exceeds UINT64_MAX method will
/// revert with a "PACKED_OVERFLOW" error message
function set(Packed memory _self, uint8 n, uint256 x) internal pure {
require(x <= UINT64_MAX, "PACKED_OVERFLOW");
_self.v = _self.v & ~(UINT64_MAX << (64 * n)) | ((x & UINT64_MAX) << (64 * n));
}

/// @dev Adds value stored in passed `x` variable to variable stored on position `n`
/// using SafeMath lib
function add(Packed memory _self, uint8 n, uint256 x) internal pure {
set(_self, n, get(_self, n).add(x));
}

/// @dev Subtract value stored in passed `x` variable from variable stored on position `n`
/// using SafeMath lib
function sub(Packed memory _self, uint8 n, uint256 x) internal pure {
set(_self, n, get(_self, n).sub(x));
}
}
2 changes: 1 addition & 1 deletion contracts/0.4.24/lib/SigningKeys.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ library SigningKeys {
bytes _pubkeys,
bytes _signatures
) internal returns (uint256) {
require(_keysCount > 0 && _startIndex.add(_keysCount - 1) <= UINT64_MAX, "INVALID_KEYS_COUNT");
require(_keysCount > 0 && _startIndex.add(_keysCount) <= UINT64_MAX, "INVALID_KEYS_COUNT");
require(
_pubkeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH),
"LENGTH_MISMATCH"
Expand Down
Loading

0 comments on commit feafec4

Please sign in to comment.