Skip to content

Commit

Permalink
PR fixes: fix comments, readme, rename bridges, notifier refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
kovalgek committed Apr 10, 2024
1 parent 3332e30 commit 0545e33
Show file tree
Hide file tree
Showing 40 changed files with 568 additions and 520 deletions.
13 changes: 5 additions & 8 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,20 @@ ETHERSCAN_API_KEY_OPT=
# Bridge/Gateway Deployment
# ############################

# Address of the token to deploy the bridge/gateway for
# Address of the token on L1 to deploy the bridge/gateway for
TOKEN=

# Address of the rebasable token to deploy the bridge/gateway for
# Address of the rebasable token on L1 to deploy the bridge/gateway for
REBASABLE_TOKEN=

# Address of token rate notifier. Connects Lido core protocol.
TOKEN_RATE_NOTIFIER=

# Address of token rate pusher
# Address of token rate pusher. Required to config TokenRateOracle.
L1_OP_STACK_TOKEN_RATE_PUSHER=

# Gas limit required to complete pushing token rate on L2.
L2_GAS_LIMIT_FOR_PUSHING_TOKEN_RATE=

# A time period when token rate can be considered outdated.
RATE_OUTDATED_DELAY=
RATE_OUTDATED_DELAY=86400 # default is 24 hours

# Address of L1 token bridge proxy.
L1_TOKEN_BRIDGE=
Expand All @@ -59,7 +56,7 @@ L2_TOKEN_RATE_ORACLE=
GOV_BRIDGE_EXECUTOR=

# Name of the network environments used by deployment scripts.
# Might be one of: "mainnet", "goerli".
# Might be one of: "mainnet", "sepolia".
NETWORK=mainnet

# Run deployment in the forking network instead of public ones
Expand Down
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ To retrieve more detailed info about the bridging process, see the specification

- [Lido's Arbitrum Gateway](https://github.com/lidofinance/lido-l2/blob/main/contracts/arbitrum/README.md).
- [Lido's Optimism Bridge](https://github.com/lidofinance/lido-l2/blob/main/contracts/optimism/README.md).
- [wstETH Bridging Guide](https://docs.lido.fi/token-guides/wsteth-bridging-guide/#r-5-bridging-l1-lido-dao-decisions)

## Project setup

Expand Down Expand Up @@ -44,7 +45,15 @@ The configuration of the deployment scripts happens via the ENV variables. The f

- [`TOKEN`](#TOKEN) - address of the non-rebasable token to deploy a new bridge on the Ethereum chain.
- [`REBASABLE_TOKEN`] (#REBASABLE_TOKEN) - address of the rebasable token to deploy new bridge on the Ethereum chain.
- [`NETWORK`](#NETWORK) - name of the network environments used by deployment scripts. Allowed values: `mainnet`, `goerli`.
- [`L1_OP_STACK_TOKEN_RATE_PUSHER`](#L1_OP_STACK_TOKEN_RATE_PUSHER) - address of token rate pusher. Required to config TokenRateOracle.
- [`L2_GAS_LIMIT_FOR_PUSHING_TOKEN_RATE`](#L2_GAS_LIMIT_FOR_PUSHING_TOKEN_RATE) - gas limit required to complete pushing token rate on L2.
- [`RATE_OUTDATED_DELAY`](#RATE_OUTDATED_DELAY) - a time period when token rate can be considered outdated. Default is 24 hours.
- [`L1_TOKEN_BRIDGE`](#L1_TOKEN_BRIDGE) - address of L1 token bridge.
- [`L2_TOKEN_BRIDGE`](#L2_TOKEN_BRIDGE) - address of L2 token bridge.
- [`L2_TOKEN`](#L2_TOKEN) - address of the non-rebasable token on L2.
- [`L2_TOKEN_RATE_ORACLE`](#L2_TOKEN_RATE_ORACLE) - address of token rate oracle on L2.
- [`GOV_BRIDGE_EXECUTOR`](#GOV_BRIDGE_EXECUTOR) - address of bridge executor.
- [`NETWORK`](#NETWORK) - name of the network environments used by deployment scripts. Allowed values: `mainnet`, `sepolia`.
- [`FORKING`](#FORKING) - run deployment in the forking network instead of real ones
- [`ETH_DEPLOYER_PRIVATE_KEY`](#ETH_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Ethereum network is used during the deployment process.
- [`ARB_DEPLOYER_PRIVATE_KEY`](#ARB_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Arbitrum network is used during the deployment process.
Expand Down Expand Up @@ -315,17 +324,17 @@ Below variables used in the Arbitrum/Optimism bridge deployment process.

#### `TOKEN`

Address of the non-rebasable token to deploy a new bridge on the Ethereum chain.
Address of the existing non-rebasable token to deploy a new bridge for on the Ethereum chain.

#### `REBASABLE_TOKEN`

Address of the rebasable token to deploy new bridge on the Ethereum chain.
Address of the existing rebasable token to deploy new bridge for on the Ethereum chain.

#### `NETWORK`

> Default value: `mainnet`
Name of the network environments used by deployment scripts. Might be one of: `mainnet`, `goerli`.
Name of the network environments used by deployment scripts. Might be one of: `mainnet`, `sepolia`.

#### `FORKING`

Expand Down Expand Up @@ -447,7 +456,7 @@ The following variables are used in the process of the Integration & E2E testing

#### `TESTING_ARB_NETWORK`

Name of the network environments used for Arbitrum Integration & E2E testing. Might be one of: `mainnet`, `goerli`.
Name of the network environments used for Arbitrum Integration & E2E testing. Might be one of: `mainnet`, `sepolia`.

#### `TESTING_ARB_L1_TOKEN`

Expand Down Expand Up @@ -487,7 +496,7 @@ Address of the L2 gateway router used in the Acceptance Integration & E2E (when
#### `TESTING_OPT_NETWORK`

Name of the network environments used for Optimism Integration & E2E testing. Might be one of: `mainnet`, `goerli`.
Name of the network environments used for Optimism Integration & E2E testing. Might be one of: `mainnet`, `sepolia`.

#### `TESTING_OPT_L1_TOKEN`

Expand Down
3 changes: 1 addition & 2 deletions contracts/lib/SignatureChecker.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2024 OpenZeppelin, Lido <info@lido.fi>
// SPDX-License-Identifier: GPL-3.0
// Writen based on (utils/cryptography/SignatureChecker.sol from d398d68
// Written based on (utils/cryptography/SignatureChecker.sol from d398d68

pragma solidity 0.8.10;

Expand All @@ -24,7 +24,6 @@ library SignatureChecker {
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
if (signer.code.length == 0) {
// return true;
(address recovered, ECDSA.RecoverError err) = ECDSA.tryRecover(hash, signature);
return err == ECDSA.RecoverError.NoError && recovered == signer;
} else {
Expand Down
48 changes: 31 additions & 17 deletions contracts/lido/TokenRateNotifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,32 @@

pragma solidity 0.8.10;

Check warning on line 4 in contracts/lido/TokenRateNotifier.sol

View workflow job for this annotation

GitHub Actions / solhint

Found more than One contract per file. 2 contracts found!

import {IPostTokenRebaseReceiver} from "./interfaces/IPostTokenRebaseReceiver.sol";
import {ITokenRatePusher} from "./interfaces/ITokenRatePusher.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

/// @notice An interface to subscribe on the `stETH` token rebases (defined in the `Lido` core contract)
interface IPostTokenRebaseReceiver {

/// @notice Is called in the context of `Lido.handleOracleReport` to notify the subscribers about each token rebase
function handlePostTokenRebase(
uint256 _reportTimestamp,
uint256 _timeElapsed,
uint256 _preTotalShares,
uint256 _preTotalEther,
uint256 _postTotalShares,
uint256 _postTotalEther,
uint256 _sharesMintedAsFees
) external;
}

/// @author kovalgek
/// @notice Notifies all observers when rebase event occures.
contract TokenRateNotifier is Ownable, IPostTokenRebaseReceiver {
using ERC165Checker for address;

/// @notice Maximum amount of observers to be supported.
uint256 public constant MAX_OBSERVERS_COUNT = 16;

/// @notice Invalid interface id.
bytes4 public constant INVALID_INTERFACE_ID = 0xffffffff;
uint256 public constant MAX_OBSERVERS_COUNT = 32;

/// @notice A value that indicates that value was not found.
uint256 public constant INDEX_NOT_FOUND = type(uint256).max;
Expand All @@ -28,6 +39,11 @@ contract TokenRateNotifier is Ownable, IPostTokenRebaseReceiver {
/// @notice All observers.
address[] public observers;

/// @param initialOwner_ initial owner
constructor(address initialOwner_) {
_transferOwnership(initialOwner_);
}

/// @notice Add a `observer_` to the back of array
/// @param observer_ observer address
function addObserver(address observer_) external onlyOwner {
Expand Down Expand Up @@ -55,24 +71,22 @@ contract TokenRateNotifier is Ownable, IPostTokenRebaseReceiver {
revert ErrorNoObserverToRemove();
}

for (uint256 obIndex = observerIndexToRemove; obIndex < observers.length - 1; obIndex++) {
observers[obIndex] = observers[obIndex + 1];
}

observers[observerIndexToRemove] = observers[observers.length - 1];
observers.pop();

emit ObserverRemoved(observer_);
}

/// @inheritdoc IPostTokenRebaseReceiver
/// @dev Parameters aren't used because all required data further components fetch by themselves.
function handlePostTokenRebase(
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256
uint256, /* reportTimestamp */
uint256, /* timeElapsed */
uint256, /* preTotalShares */
uint256, /* preTotalEther */
uint256, /* postTotalShares */
uint256, /* postTotalEther */
uint256 /* sharesMintedAsFees */
) external {
for (uint256 obIndex = 0; obIndex < observers.length; obIndex++) {
try ITokenRatePusher(observers[obIndex]).pushTokenRate() {}

Check warning on line 92 in contracts/lido/TokenRateNotifier.sol

View workflow job for this annotation

GitHub Actions / solhint

Code contains empty blocks
Expand All @@ -93,7 +107,7 @@ contract TokenRateNotifier is Ownable, IPostTokenRebaseReceiver {

/// @notice Observer length
/// @return Added observers count
function observersLength() public view returns (uint256) {
function observersLength() external view returns (uint256) {
return observers.length;
}

Expand Down
20 changes: 0 additions & 20 deletions contracts/lido/interfaces/IPostTokenRebaseReceiver.sol

This file was deleted.

4 changes: 2 additions & 2 deletions contracts/lido/interfaces/ITokenRatePusher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
pragma solidity 0.8.10;

/// @author kovalgek
/// @notice An interface for entity that pushes rate.
/// @notice An interface for entity that pushes token rate.
interface ITokenRatePusher {
/// @notice Pushes token rate to L2 by depositing zero tokens.
/// @notice Pushes token rate to L2 by depositing zero token amount.
function pushTokenRate() external;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

contract OpStackTokenRatePusherWithOutOfGasErrorStub is ERC165, ITokenRatePusher {

mapping (uint256 => uint256) data;
uint256 public constant OUT_OF_GAS_INCURRING_MAX = 1000000000000;

mapping (uint256 => uint256) public data;

function pushTokenRate() external {
for (uint256 i = 0; i < 1000000000000; ++i) {
for (uint256 i = 0; i < OUT_OF_GAS_INCURRING_MAX; ++i) {
data[i] = i;
}
}
Expand Down
8 changes: 4 additions & 4 deletions contracts/optimism/DepositDataCodec.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// SPDX-FileCopyrightText: 2024 Lido <info@lido.fi>
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;
Expand All @@ -9,7 +9,7 @@ contract DepositDataCodec {

uint8 internal constant RATE_FIELD_SIZE = 12;
uint8 internal constant TIMESTAMP_FIELD_SIZE = 5;

struct DepositData {
uint96 rate;
uint40 timestamp;
Expand All @@ -26,11 +26,11 @@ contract DepositDataCodec {
}

function decodeDepositData(bytes calldata buffer) internal pure returns (DepositData memory) {

if (buffer.length < RATE_FIELD_SIZE + TIMESTAMP_FIELD_SIZE) {
revert ErrorDepositDataLength();
}

DepositData memory depositData = DepositData({
rate: uint96(bytes12(buffer[0:RATE_FIELD_SIZE])),
timestamp: uint40(bytes5(buffer[RATE_FIELD_SIZE:RATE_FIELD_SIZE + TIMESTAMP_FIELD_SIZE])),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {IERC20WstETH} from "../token/interfaces/IERC20WstETH.sol";
/// @notice The L1 ERC20 token bridge locks bridged tokens on the L1 side, sends deposit messages
/// on the L2 side, and finalizes token withdrawals from L2. Additionally, adds the methods for
/// bridging management: enabling and disabling withdrawals/deposits
abstract contract L1ERC20TokenBridge is
abstract contract L1ERC20ExtendedTokensBridge is
IL1ERC20Bridge,
BridgingManager,
RebasableAndNonRebasableTokens,
Expand All @@ -44,7 +44,12 @@ abstract contract L1ERC20TokenBridge is
address l1TokenRebasable_,
address l2TokenNonRebasable_,
address l2TokenRebasable_
) CrossDomainEnabled(messenger_) RebasableAndNonRebasableTokens(l1TokenNonRebasable_, l1TokenRebasable_, l2TokenNonRebasable_, l2TokenRebasable_) {
) CrossDomainEnabled(messenger_) RebasableAndNonRebasableTokens(
l1TokenNonRebasable_,
l1TokenRebasable_,
l2TokenNonRebasable_,
l2TokenRebasable_
) {
L2_TOKEN_BRIDGE = l2TokenBridge_;
}

Expand Down
8 changes: 4 additions & 4 deletions contracts/optimism/L1LidoTokensBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

pragma solidity 0.8.10;

import {L1ERC20TokenBridge} from "./L1ERC20TokenBridge.sol";
import {L1ERC20ExtendedTokensBridge} from "./L1ERC20ExtendedTokensBridge.sol";
import {IERC20WstETH} from "../token/interfaces/IERC20WstETH.sol";

/// @author kovalgek
/// @notice Hides wstETH concept from other contracts to keep `L1ERC20TokenBridge` reusable.
contract L1LidoTokensBridge is L1ERC20TokenBridge {
/// @notice Hides wstETH concept from other contracts to keep `L1ERC20ExtendedTokensBridge` reusable.
contract L1LidoTokensBridge is L1ERC20ExtendedTokensBridge {

constructor(
address messenger_,
Expand All @@ -17,7 +17,7 @@ contract L1LidoTokensBridge is L1ERC20TokenBridge {
address l1TokenRebasable_,
address l2TokenNonRebasable_,
address l2TokenRebasable_
) L1ERC20TokenBridge(
) L1ERC20ExtendedTokensBridge(
messenger_,
l2TokenBridge_,
l1TokenNonRebasable_,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {DepositDataCodec} from "./DepositDataCodec.sol";
/// deposits into the L1 token bridge. It also acts as a burner of the tokens
/// intended for withdrawal, informing the L1 bridge to release L1 funds. Additionally, adds
/// the methods for bridging management: enabling and disabling withdrawals/deposits
contract L2ERC20TokenBridge is
contract L2ERC20ExtendedTokensBridge is
IL2ERC20Bridge,
BridgingManager,
RebasableAndNonRebasableTokens,
Expand All @@ -48,7 +48,12 @@ contract L2ERC20TokenBridge is
address l1TokenRebasable_,
address l2TokenNonRebasable_,
address l2TokenRebasable_
) CrossDomainEnabled(messenger_) RebasableAndNonRebasableTokens(l1TokenNonRebasable_, l1TokenRebasable_, l2TokenNonRebasable_, l2TokenRebasable_) {
) CrossDomainEnabled(messenger_) RebasableAndNonRebasableTokens(
l1TokenNonRebasable_,
l1TokenRebasable_,
l2TokenNonRebasable_,
l2TokenRebasable_
) {
L1_TOKEN_BRIDGE = l1TokenBridge_;
}

Expand Down Expand Up @@ -95,6 +100,7 @@ contract L2ERC20TokenBridge is
{
if (_isRebasableTokenFlow(l1Token_, l2Token_)) {
DepositData memory depositData = decodeDepositData(data_);

ITokenRateOracle tokenRateOracle = ERC20Rebasable(L2_TOKEN_REBASABLE).TOKEN_RATE_ORACLE();
tokenRateOracle.updateRate(depositData.rate, depositData.timestamp);

Expand Down
Loading

0 comments on commit 0545e33

Please sign in to comment.