Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] wstETH on Mantle, DON'T MERGE #52

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .env.wsteth.mnt_goerli
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Detailed info: https://github.com/lidofinance/lido-l2#Project-Configuration

# ############################
# RPCs
# ############################

RPC_ETH_GOERLI=https://eth-goerli.g.alchemy.com/v2/
RPC_MNT_GOERLI=https://rpc.testnet.mantle.xyz

# ############################
# Etherscan
# ############################

ETHERSCAN_API_KEY_ETH=
ETHERSCAN_API_KEY_MNT=

# ############################
# Bridge/Gateway Deployment
# ############################

# Address of the token to deploy the bridge/gateway for wstETH
TOKEN=0x6320cd32aa674d2898a68ec82e869385fc5f7e2f

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

# Private key of the deployer account used for deployment process
ETH_DEPLOYER_PRIVATE_KEY=
MNT_DEPLOYER_PRIVATE_KEY=

L1_PROXY_ADMIN=0x4333218072D5d7008546737786663c38B4D561A4
L1_BRIDGE_ADMIN=0x4333218072D5d7008546737786663c38B4D561A4
L1_DEPOSITS_ENABLED=true
L1_WITHDRAWALS_ENABLED=true
L1_DEPOSITS_ENABLERS=["0x4333218072D5d7008546737786663c38B4D561A4"]
L1_DEPOSITS_DISABLERS="["0x4333218072D5d7008546737786663c38B4D561A4", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd","0xa6688D0DcAd346eCc275cda98c91086fEC3fE31C"]"
L1_WITHDRAWALS_ENABLERS=["0x4333218072D5d7008546737786663c38B4D561A4"]
L1_WITHDRAWALS_DISABLERS="["0x4333218072D5d7008546737786663c38B4D561A4", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd","0xa6688D0DcAd346eCc275cda98c91086fEC3fE31C"]"

L2_PROXY_ADMIN=0xaF3dcfddBbBC59E7d2ec6f6e4273f7F1a3C7B6fe
L2_BRIDGE_ADMIN=0xaF3dcfddBbBC59E7d2ec6f6e4273f7F1a3C7B6fe
L2_DEPOSITS_ENABLED=true
L2_WITHDRAWALS_ENABLED=true
L2_DEPOSITS_ENABLERS=["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35"]
L2_DEPOSITS_DISABLERS="["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"]"
L2_WITHDRAWALS_ENABLERS=["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35"]
L2_WITHDRAWALS_DISABLERS="["0x55C39356C714Cde16F8a80302c1Ce9DfAC6f5a35", "0x7fE7fa4EF7D134Dbf8B616Ba7B675F26286BC2cd"]"

# ############################
# Integration & E2E Testing
# ############################

TESTING_MNT_NETWORK=goerli
TESTING_MNT_L1_TOKEN=0x6320cd32aa674d2898a68ec82e869385fc5f7e2f
TESTING_MNT_L2_TOKEN=0xe8964a99d5DE7cEE2743B20113a52C953b0916E9
TESTING_MNT_L1_ERC20_TOKEN_BRIDGE=0xDdC89Bd27F9A1C47A5c20dF0783dE52f55513598
TESTING_MNT_L2_ERC20_TOKEN_BRIDGE=0x423702bC3Fb92f59Be440354456f0481934bF1f5

# ############################
# Integration Testing
# ############################

TESTING_USE_DEPLOYED_CONTRACTS=true
TESTING_L1_TOKENS_HOLDER=

# ############################
# E2E Testing
# ############################

TESTING_PRIVATE_KEY=
74 changes: 74 additions & 0 deletions .env.wsteth.mnt_mainnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Detailed info: https://github.com/lidofinance/lido-l2#Project-Configuration

# ############################
# RPCs
# ############################

RPC_ETH_MAINNET=
RPC_OPT_MAINNET=

# ############################
# Etherscan
# ############################

ETHERSCAN_API_KEY_ETH=
ETHERSCAN_API_KEY_OPT=

# ############################
# Bridge/Gateway Deployment
# ############################

# Address of the token to deploy the bridge/gateway for
TOKEN=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0

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

# Run deployment in the forking network instead of public ones
FORKING=true

# Private key of the deployer account used for deployment process
ETH_DEPLOYER_PRIVATE_KEY=
OPT_DEPLOYER_PRIVATE_KEY=

L1_PROXY_ADMIN=0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c
L1_BRIDGE_ADMIN=0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c
L1_DEPOSITS_ENABLED=false
L1_WITHDRAWALS_ENABLED=true
L1_DEPOSITS_ENABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c","0x3cd9F71F80AB08ea5a7Dca348B5e94BC595f26A0"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove the dev msig

L1_DEPOSITS_DISABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c","0x73b047fe6337183A454c5217241D780a932777bD"]
L1_WITHDRAWALS_ENABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c"]
L1_WITHDRAWALS_DISABLERS=["0x3e40D73EB977Dc6a537aF587D48316feE66E9C8c","0x73b047fe6337183A454c5217241D780a932777bD"]

L2_PROXY_ADMIN=0xEfa0dB536d2c8089685630fafe88CF7805966FC3
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimism

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No Safe on Mantle?

L2_BRIDGE_ADMIN=0xEfa0dB536d2c8089685630fafe88CF7805966FC3
L2_DEPOSITS_ENABLED=true
L2_WITHDRAWALS_ENABLED=true
L2_DEPOSITS_ENABLERS=["0xEfa0dB536d2c8089685630fafe88CF7805966FC3"]
L2_DEPOSITS_DISABLERS=["0xEfa0dB536d2c8089685630fafe88CF7805966FC3","0x4Cf8fE0A4c2539F7EFDD2047d8A5D46F14613088"]
L2_WITHDRAWALS_ENABLERS=["0xEfa0dB536d2c8089685630fafe88CF7805966FC3"]
L2_WITHDRAWALS_DISABLERS=["0xEfa0dB536d2c8089685630fafe88CF7805966FC3","0x4Cf8fE0A4c2539F7EFDD2047d8A5D46F14613088"]

# ############################
# Integration Acceptance & E2E Testing
# ############################

TESTING_OPT_NETWORK=mainnet
TESTING_OPT_L1_TOKEN=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
TESTING_OPT_L2_TOKEN=0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb
TESTING_OPT_L1_ERC20_TOKEN_BRIDGE=0x76943C0D61395d8F2edF9060e1533529cAe05dE6
TESTING_OPT_L2_ERC20_TOKEN_BRIDGE=0x8E01013243a96601a86eb3153F0d9Fa4fbFb6957

# ############################
# Integration Testing
# ############################

TESTING_USE_DEPLOYED_CONTRACTS=true
TESTING_L1_TOKENS_HOLDER=

# ############################
# E2E Testing
# ############################

TESTING_PRIVATE_KEY=
2 changes: 1 addition & 1 deletion .solcover.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
skipFiles: ["stubs", "optimism/stubs", "proxy/stubs", "arbitrum/stubs"],
skipFiles: ["stubs", "optimism/stubs", "proxy/stubs", "arbitrum/stubs", "mantle/stubs"],
};
46 changes: 46 additions & 0 deletions contracts/mantle/CrossDomainEnabled.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: 2022 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

import {ICrossDomainMessenger} from "./interfaces/ICrossDomainMessenger.sol";

/// @dev Helper contract for contracts performing cross-domain communications
contract CrossDomainEnabled {
/// @notice Messenger contract used to send and receive messages from the other domain
ICrossDomainMessenger public immutable messenger;

Check warning on line 11 in contracts/mantle/CrossDomainEnabled.sol

View workflow job for this annotation

GitHub Actions / solhint

Immutable variables name are set to be in capitalized SNAKE_CASE

/// @param messenger_ Address of the CrossDomainMessenger on the current layer
constructor(address messenger_) {
messenger = ICrossDomainMessenger(messenger_);
}

/// @dev Sends a message to an account on another domain
/// @param crossDomainTarget_ Intended recipient on the destination domain
/// @param message_ Data to send to the target (usually calldata to a function with
/// `onlyFromCrossDomainAccount()`)
/// @param gasLimit_ gasLimit for the receipt of the message on the target domain.
function sendCrossDomainMessage(
address crossDomainTarget_,
uint32 gasLimit_,
bytes memory message_
) internal {
messenger.sendMessage(crossDomainTarget_, message_, gasLimit_);
}

/// @dev Enforces that the modified function is only callable by a specific cross-domain account
/// @param sourceDomainAccount_ The only account on the originating domain which is
/// authenticated to call this function
modifier onlyFromCrossDomainAccount(address sourceDomainAccount_) {
if (msg.sender != address(messenger)) {
revert ErrorUnauthorizedMessenger();
}
if (messenger.xDomainMessageSender() != sourceDomainAccount_) {
revert ErrorWrongCrossDomainSender();
}
_;
}

error ErrorUnauthorizedMessenger();
error ErrorWrongCrossDomainSender();
}
Comment on lines +9 to +46

Check failure

Code scanning / Slither

Name reused High

CrossDomainEnabled is re-used:
- CrossDomainEnabled
- CrossDomainEnabled
150 changes: 150 additions & 0 deletions contracts/mantle/L1ERC20TokenBridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// SPDX-FileCopyrightText: 2022 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {IL1ERC20Bridge} from "./interfaces/IL1ERC20Bridge.sol";
import {IL2ERC20Bridge} from "./interfaces/IL2ERC20Bridge.sol";

import {BridgingManager} from "../BridgingManager.sol";
import {BridgeableTokens} from "../BridgeableTokens.sol";
import {CrossDomainEnabled} from "./CrossDomainEnabled.sol";

/// @author psirex
/// @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
contract L1ERC20TokenBridge is
IL1ERC20Bridge,
BridgingManager,
BridgeableTokens,
CrossDomainEnabled
{
using SafeERC20 for IERC20;

/// @inheritdoc IL1ERC20Bridge
address public immutable l2TokenBridge;

Check warning on line 30 in contracts/mantle/L1ERC20TokenBridge.sol

View workflow job for this annotation

GitHub Actions / solhint

Immutable variables name are set to be in capitalized SNAKE_CASE

/// @param messenger_ L1 messenger address being used for cross-chain communications
/// @param l2TokenBridge_ Address of the corresponding L2 bridge
/// @param l1Token_ Address of the bridged token in the L1 chain
/// @param l2Token_ Address of the token minted on the L2 chain when token bridged
constructor(
address messenger_,
address l2TokenBridge_,
address l1Token_,
address l2Token_
) CrossDomainEnabled(messenger_) BridgeableTokens(l1Token_, l2Token_) {
l2TokenBridge = l2TokenBridge_;
}

/// @inheritdoc IL1ERC20Bridge
function depositERC20(
address l1Token_,
address l2Token_,
uint256 amount_,
uint32 l2Gas_,
bytes calldata data_
)
external
whenDepositsEnabled
onlySupportedL1Token(l1Token_)
onlySupportedL2Token(l2Token_)
{
if (Address.isContract(msg.sender)) {
revert ErrorSenderNotEOA();
}
_initiateERC20Deposit(msg.sender, msg.sender, amount_, l2Gas_, data_);
}

/// @inheritdoc IL1ERC20Bridge
function depositERC20To(
address l1Token_,
address l2Token_,
address to_,
uint256 amount_,
uint32 l2Gas_,
bytes calldata data_
)
external
whenDepositsEnabled
onlyNonZeroAccount(to_)
onlySupportedL1Token(l1Token_)
onlySupportedL2Token(l2Token_)
{
_initiateERC20Deposit(msg.sender, to_, amount_, l2Gas_, data_);
}

/// @inheritdoc IL1ERC20Bridge
function finalizeERC20Withdrawal(
address l1Token_,
address l2Token_,
address from_,
address to_,
uint256 amount_,
bytes calldata data_
)
external
whenWithdrawalsEnabled
onlySupportedL1Token(l1Token_)
onlySupportedL2Token(l2Token_)
onlyFromCrossDomainAccount(l2TokenBridge)
{
IERC20(l1Token_).safeTransfer(to_, amount_);

emit ERC20WithdrawalFinalized(
l1Token_,
l2Token_,
from_,
to_,
amount_,
data_
);
}

/// @dev Performs the logic for deposits by informing the L2 token bridge contract
/// of the deposit and calling safeTransferFrom to lock the L1 funds.
/// @param from_ Account to pull the deposit from on L1
/// @param to_ Account to give the deposit to on L2
/// @param amount_ Amount of the ERC20 to deposit.
/// @param l2Gas_ Gas limit required to complete the deposit on L2.
/// @param data_ Optional data to forward to L2. This data is provided
/// solely as a convenience for external contracts. Aside from enforcing a maximum
/// length, these contracts provide no guarantees about its content.
function _initiateERC20Deposit(
address from_,
address to_,
uint256 amount_,
uint32 l2Gas_,
bytes calldata data_
) internal {
IERC20(l1Token).safeTransferFrom(from_, address(this), amount_);

bytes memory message = abi.encodeWithSelector(
IL2ERC20Bridge.finalizeDeposit.selector,
l1Token,
l2Token,
from_,
to_,
amount_,
data_
);

sendCrossDomainMessage(l2TokenBridge, l2Gas_, message);

emit ERC20DepositInitiated(
l1Token,
l2Token,
from_,
to_,
amount_,
data_
);
}

error ErrorSenderNotEOA();
}
Comment on lines +21 to +150

Check failure

Code scanning / Slither

Name reused High

L1ERC20TokenBridge is re-used:
- L1ERC20TokenBridge
- L1ERC20TokenBridge
Loading
Loading