Skip to content

Commit f2079fd

Browse files
committed
Merge branch 'feat/vaults' into feat/vaults-fuzzing
2 parents 7e52fb5 + fb4f7e5 commit f2079fd

File tree

160 files changed

+4967
-3520
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

160 files changed

+4967
-3520
lines changed

.github/workflows/coverage.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ jobs:
99
coverage:
1010
name: Hardhat
1111
runs-on: ubuntu-latest
12+
env:
13+
NODE_OPTIONS: --max_old_space_size=6400
1214

1315
permissions:
1416
contents: write
@@ -30,7 +32,7 @@ jobs:
3032
path: ./coverage/cobertura-coverage.xml
3133
publish: true
3234
# TODO: restore to 95% before release
33-
threshold: 90
35+
threshold: 80
3436
diff: true
3537
diff-branch: master
3638
diff-storage: _core_coverage_reports

.github/workflows/tests-integration-mainnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
GAS_PRIORITY_FEE: 1
3737
GAS_MAX_FEE: 100
3838
NETWORK_STATE_FILE: deployed-mainnet-upgrade.json
39-
UPGRADE_PARAMETERS_FILE: upgrade-parameters-mainnet.json
39+
GENESIS_TIME: 1606824023 # needed only for TW upgrade
4040

4141
- name: Mock Aragon voting
4242
run: yarn upgrade:mock-voting

.github/workflows/tests-integration-upgrade-template.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ jobs:
2222
env:
2323
RPC_URL: "${{ secrets.ETH_RPC_URL }}"
2424
UPGRADE_PARAMETERS_FILE: upgrade-parameters-mainnet.json
25+
GENESIS_TIME: 1606824023 # needed only for TW upgrade

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
yarn lint-staged
2-
yarn typecheck
32
yarn compile
3+
yarn typecheck

.solcover.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ module.exports = {
1212
"common/lib", // 100% covered by test/common/*.t.sol
1313
"0.8.9/lib/UnstructuredStorage.sol", // 100% covered by test/0.8.9/unstructuredStorage.t.sol
1414
"openzeppelin",
15+
"testnet",
16+
"upgrade",
1517
],
1618
};

contracts/0.4.24/Lido.sol

Lines changed: 206 additions & 102 deletions
Large diffs are not rendered by default.

contracts/0.4.24/StETH.sol

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {IERC20} from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
88
import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol";
99
import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol";
1010
import {Pausable} from "./utils/Pausable.sol";
11+
import {UnstructuredStorageUint128} from "./utils/UnstructuredStorageUint128.sol";
1112

1213
/**
1314
* @title Interest-bearing ERC20-like token for Lido Liquid Stacking protocol.
@@ -49,9 +50,11 @@ import {Pausable} from "./utils/Pausable.sol";
4950
contract StETH is IERC20, Pausable {
5051
using SafeMath for uint256;
5152
using UnstructuredStorage for bytes32;
53+
using UnstructuredStorageUint128 for bytes32;
5254

5355
address constant internal INITIAL_TOKEN_HOLDER = 0xdead;
5456
uint256 constant internal INFINITE_ALLOWANCE = ~uint256(0);
57+
uint256 constant internal UINT128_MAX = ~uint128(0);
5558

5659
/**
5760
* @dev StETH balances are dynamic and are calculated based on the accounts' shares
@@ -82,6 +85,8 @@ contract StETH is IERC20, Pausable {
8285
* see https://github.com/lidofinance/lido-dao/issues/181#issuecomment-736098834
8386
*
8487
* keccak256("lido.StETH.totalShares")
88+
*
89+
* @dev Since version 3, high 128 bits can be used to store the external shares from Lido contract
8590
*/
8691
bytes32 internal constant TOTAL_SHARES_POSITION =
8792
0xe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e;
@@ -299,37 +304,45 @@ contract StETH is IERC20, Pausable {
299304
}
300305

301306
/**
307+
* @param _ethAmount the amount of ether to convert to shares. Must be less than UINT128_MAX.
302308
* @return the amount of shares that corresponds to `_ethAmount` protocol-controlled Ether.
309+
* @dev the result is rounded down.
303310
*/
304311
function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) {
305-
return _ethAmount
306-
.mul(_getShareRateDenominator()) // denominator in shares
307-
.div(_getShareRateNumerator()); // numerator in ether
312+
require(_ethAmount < UINT128_MAX, "ETH_TOO_LARGE");
313+
return (_ethAmount
314+
* _getShareRateDenominator()) // denominator in shares
315+
/ _getShareRateNumerator(); // numerator in ether
308316
}
309317

310318
/**
319+
* @param _sharesAmount the amount of shares to convert to ether. Must be less than UINT128_MAX.
311320
* @return the amount of ether that corresponds to `_sharesAmount` token shares.
321+
* @dev the result is rounded down.
312322
*/
313323
function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) {
314-
return _sharesAmount
315-
.mul(_getShareRateNumerator()) // numerator in ether
316-
.div(_getShareRateDenominator()); // denominator in shares
324+
require(_sharesAmount < UINT128_MAX, "SHARES_TOO_LARGE");
325+
return (_sharesAmount
326+
* _getShareRateNumerator()) // numerator in ether
327+
/ _getShareRateDenominator(); // denominator in shares
317328
}
318329

319330
/**
331+
* @param _sharesAmount the amount of shares to convert to ether. Must be less than UINT128_MAX.
320332
* @return the amount of ether that corresponds to `_sharesAmount` token shares.
321333
* @dev The result is rounded up. So,
322334
* for `shareRate >= 0.5`, `getSharesByPooledEth(getPooledEthBySharesRoundUp(1))` will be 1.
323335
*/
324336
function getPooledEthBySharesRoundUp(uint256 _sharesAmount) public view returns (uint256 etherAmount) {
337+
require(_sharesAmount < UINT128_MAX, "SHARES_TOO_LARGE");
325338
uint256 numeratorInEther = _getShareRateNumerator();
326339
uint256 denominatorInShares = _getShareRateDenominator();
327340

328-
etherAmount = _sharesAmount
329-
.mul(numeratorInEther)
330-
.div(denominatorInShares);
341+
etherAmount = (_sharesAmount
342+
* numeratorInEther)
343+
/ denominatorInShares;
331344

332-
if (_sharesAmount.mul(numeratorInEther) != etherAmount.mul(denominatorInShares)) {
345+
if (_sharesAmount * numeratorInEther != etherAmount * denominatorInShares) {
333346
++etherAmount;
334347
}
335348
}
@@ -392,6 +405,7 @@ contract StETH is IERC20, Pausable {
392405
/**
393406
* @return the numerator of the protocol's share rate (in ether).
394407
* @dev used to convert shares to tokens and vice versa.
408+
* @dev can be overridden in a derived contract.
395409
*/
396410
function _getShareRateNumerator() internal view returns (uint256) {
397411
return _getTotalPooledEther();
@@ -400,6 +414,7 @@ contract StETH is IERC20, Pausable {
400414
/**
401415
* @return the denominator of the protocol's share rate (in shares).
402416
* @dev used to convert shares to tokens and vice versa.
417+
* @dev can be overridden in a derived contract.
403418
*/
404419
function _getShareRateDenominator() internal view returns (uint256) {
405420
return _getTotalShares();
@@ -456,7 +471,7 @@ contract StETH is IERC20, Pausable {
456471
* @return the total amount of shares in existence.
457472
*/
458473
function _getTotalShares() internal view returns (uint256) {
459-
return TOTAL_SHARES_POSITION.getStorageUint256();
474+
return TOTAL_SHARES_POSITION.getLowUint128();
460475
}
461476

462477
/**
@@ -504,7 +519,7 @@ contract StETH is IERC20, Pausable {
504519
require(_recipient != address(0), "MINT_TO_ZERO_ADDR");
505520

506521
newTotalShares = _getTotalShares().add(_sharesAmount);
507-
TOTAL_SHARES_POSITION.setStorageUint256(newTotalShares);
522+
TOTAL_SHARES_POSITION.setLowUint128(uint128(newTotalShares));
508523

509524
shares[_recipient] = shares[_recipient].add(_sharesAmount);
510525

@@ -535,7 +550,7 @@ contract StETH is IERC20, Pausable {
535550
uint256 preRebaseTokenAmount = getPooledEthByShares(_sharesAmount);
536551

537552
newTotalShares = _getTotalShares().sub(_sharesAmount);
538-
TOTAL_SHARES_POSITION.setStorageUint256(newTotalShares);
553+
TOTAL_SHARES_POSITION.setLowUint128(uint128(newTotalShares));
539554

540555
shares[_account] = accountShares.sub(_sharesAmount);
541556

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
2+
// SPDX-License-Identifier: GPL-3.0
3+
4+
5+
// See contracts/COMPILERS.md
6+
// solhint-disable-next-line
7+
pragma solidity 0.4.24;
8+
9+
10+
import {UnstructuredStorage} from "@aragon/os/contracts/apps/AragonApp.sol";
11+
12+
library UnstructuredStorageUint128 {
13+
using UnstructuredStorage for bytes32;
14+
15+
uint256 constant internal UINT128_LOW_MASK = ~uint128(0);
16+
uint256 constant internal UINT128_HIGH_MASK = UINT128_LOW_MASK << 128;
17+
uint256 constant internal UINT160_LOW_MASK = ~uint160(0);
18+
uint256 constant internal UINT96_HIGH_MASK = UINT160_LOW_MASK << 160;
19+
20+
function getLowUint128(bytes32 position) internal view returns (uint256) {
21+
return position.getStorageUint256() & UINT128_LOW_MASK;
22+
}
23+
24+
function setLowUint128(bytes32 position, uint256 data) internal {
25+
uint256 high128 = position.getStorageUint256() & UINT128_HIGH_MASK;
26+
position.setStorageUint256(high128 | (data & UINT128_LOW_MASK));
27+
}
28+
29+
function getHighUint128(bytes32 position) internal view returns (uint256) {
30+
return position.getStorageUint256() >> 128;
31+
}
32+
33+
function setHighUint128(bytes32 position, uint256 data) internal {
34+
uint256 low128 = position.getStorageUint256() & UINT128_LOW_MASK;
35+
position.setStorageUint256((data << 128) | low128);
36+
}
37+
38+
function getLowAndHighUint128(bytes32 position) internal view returns (uint256 low, uint256 high) {
39+
uint256 value = position.getStorageUint256();
40+
low = value & UINT128_LOW_MASK;
41+
high = value >> 128;
42+
}
43+
44+
function setLowAndHighUint128(bytes32 position, uint256 low, uint256 high) internal {
45+
position.setStorageUint256((high << 128) | (low & UINT128_LOW_MASK));
46+
}
47+
48+
function getLowUint160(bytes32 position) internal view returns (uint256) {
49+
return position.getStorageUint256() & UINT160_LOW_MASK;
50+
}
51+
52+
function setLowUint160(bytes32 position, uint256 data) internal {
53+
position.setStorageUint256((position.getStorageUint256() & UINT96_HIGH_MASK) | (data & UINT160_LOW_MASK));
54+
}
55+
56+
function getHighUint96(bytes32 position) internal view returns (uint256) {
57+
return position.getStorageUint256() >> 160;
58+
}
59+
60+
function setHighUint96(bytes32 position, uint256 data) internal {
61+
position.setStorageUint256((data << 160) | (position.getStorageUint256() & UINT160_LOW_MASK));
62+
}
63+
}

contracts/0.8.25/ValidatorExitDelayVerifier.sol

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33

44
pragma solidity 0.8.25;
55

6-
import {BeaconBlockHeader, Validator} from "../common/lib/BeaconTypes.sol";
7-
import {GIndex} from "../common/lib/GIndex.sol";
8-
import {SSZ} from "../common/lib/SSZ.sol";
9-
import {ILidoLocator} from "../common/interfaces/ILidoLocator.sol";
10-
import {IValidatorsExitBus} from "./interfaces/IValidatorsExitBus.sol";
11-
import {IStakingRouter} from "./interfaces/IStakingRouter.sol";
6+
import {IStakingRouter} from "contracts/common/interfaces/IStakingRouter.sol";
7+
import {BeaconBlockHeader, Validator} from "contracts/common/lib/BeaconTypes.sol";
8+
import {GIndex} from "contracts/common/lib/GIndex.sol";
9+
import {SSZ} from "contracts/common/lib/SSZ.sol";
10+
import {ILidoLocator} from "contracts/common/interfaces/ILidoLocator.sol";
11+
import {IValidatorsExitBus} from "contracts/common/interfaces/IValidatorsExitBus.sol";
1212

1313
struct ExitRequestData {
1414
bytes data;

contracts/0.8.25/interfaces/IPostTokenRebaseReceiver.sol

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)