-
Notifications
You must be signed in to change notification settings - Fork 358
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
Kl/without 1.5.0 merge dev #331
Changes from 134 commits
587fc6f
56cfe4b
08fcdc3
fed442f
a975413
1cc2c80
5eaf3fa
89ebe8e
5cf9582
34a9cd5
5a32908
a21571b
30f8956
4befd8a
c6be4c7
445bcf7
cff36f9
8f4c5b0
ee5ca89
021b1c0
38147a6
ee7bd5a
db1130f
78d4951
622a801
df9f325
488d15b
bc02bed
0b93956
8a5de19
207d195
ceb100f
094f57f
bd9e94d
a5dfc6a
bbbe9e9
24c8be7
f360d0e
af562bd
3f92673
ca34c4b
ca524ce
8cd5184
3998cad
88e3c7c
60cf175
39abd6c
b2ea1b5
72a49c6
882e4e7
42bacf9
ced6472
a1bd4cc
0c3e2d2
4dc74b8
4ba6bcf
46f85d4
d66e55f
2194747
15293e4
a19cd47
dc4d1b6
6aef3b7
3be4efc
efb9af3
b7b61ef
a30ecb6
b5d7fc5
98ee7e5
5eb45d2
38c1237
27e3ba8
7de6499
d70e5e0
97f2a83
964c1d0
affa83d
45ee4ae
4844258
d023451
bc40ba2
742c131
bf2a357
e78c5c3
76cd777
17daf4a
8c4e10a
434ef23
f4e562a
2d54bcd
91b657d
9026685
52d2d46
6770c0b
f403e23
ee2717b
c43cf97
96c9814
9a1d6a1
1b42052
1fd4cd8
6c82491
ae16bd5
2e21950
27fc259
f33e767
c706d00
4b3ea16
95e5571
032427b
6ca20c6
40d0f60
c88cb6f
80d3067
6a9a0d0
da97cae
dab2a1f
d32f4a3
8656a58
a2f0167
6f8ae38
f168e54
a60710d
53a0a21
5e033da
857eada
95da499
76acbf5
a997ae6
77d1cc8
77ec2bb
74311c2
bb39921
abe934f
90c869e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,7 @@ | |
|
||
pragma solidity 0.8.24; | ||
|
||
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; | ||
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; | ||
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; | ||
|
||
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; | ||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
@@ -27,25 +26,42 @@ | |
/// @custom:security-contact [email protected] | ||
/// @dev Bridges assets between L1 and hyperchains, supporting both ETH and ERC20 tokens. | ||
/// @dev Designed for use with a proxy for upgradability. | ||
contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Initializable, Ownable2Step { | ||
contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgradeable { | ||
using SafeERC20 for IERC20; | ||
|
||
/// @dev The address of the WETH token on L1. | ||
address public immutable override l1WethAddress; | ||
Check warning on line 33 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
Check warning on line 33 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
|
||
|
||
/// @dev Bridgehub smart contract that is used to operate with L2 via asynchronous L2 <-> L1 communication. | ||
IBridgehub public immutable override bridgehub; | ||
Check warning on line 36 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
Check warning on line 36 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
|
||
|
||
/// @dev Era's chainID | ||
uint256 immutable eraChainId; | ||
Check warning on line 39 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
Check warning on line 39 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
|
||
|
||
/// @dev The address of zkSync Era diamond proxy contract. | ||
address immutable eraDiamondProxy; | ||
Check warning on line 42 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
Check warning on line 42 in l1-contracts/contracts/bridge/L1SharedBridge.sol GitHub Actions / lint
|
||
|
||
/// @dev Stores the first batch number on the zkSync Era Diamond Proxy that was settled after Shared Bridge upgrade. | ||
/// This variable is used to differentiate between pre-upgrade and post-upgrade withdrawals. Withdrawals from batches older | ||
/// @dev Stores the first batch number on the zkSync Era Diamond Proxy that was settled after Diamond proxy upgrade. | ||
/// This variable is used to differentiate between pre-upgrade and post-upgrade Eth withdrawals. Withdrawals from batches older | ||
/// than this value are considered to have been finalized prior to the upgrade and handled separately. | ||
uint256 internal eraFirstPostUpgradeBatch; | ||
uint256 internal eraPostDiamondUpgradeFirstBatch; | ||
|
||
/// @dev Stores the first batch number on the zkSync Era Diamond Proxy that was settled after L1ERC20 Bridge upgrade. | ||
/// This variable is used to differentiate between pre-upgrade and post-upgrade ERC20 withdrawals. Withdrawals from batches older | ||
/// than this value are considered to have been finalized prior to the upgrade and handled separately. | ||
uint256 internal eraPostLegacyBridgeUpgradeFirstBatch; | ||
|
||
/// @dev Stores the zkSync Era batch number that processes the last deposit tx initiated by the legacy bridge | ||
/// This variable (together with eraLegacyBridgeLastDepositTxNumber) is used to differentiate between pre-upgrade and post-upgrade deposits. Deposits processed in older batches | ||
/// than this value are considered to have been processed prior to the upgrade and handled separately. | ||
/// We use this both for Eth and erc20 token deposits, so we need to update the diamond and bridge simultaneously. | ||
uint256 internal eraLegacyBridgeLastDepositBatch; | ||
|
||
/// @dev The tx number in the _eraLegacyBridgeLastDepositBatch of the last deposit tx initiated by the legacy bridge | ||
/// This variable (together with eraLegacyBridgeLastDepositBatch) is used to differentiate between pre-upgrade and post-upgrade deposits. Deposits processed in older txs | ||
/// than this value are considered to have been processed prior to the upgrade and handled separately. | ||
/// We use this both for Eth and erc20 token deposits, so we need to update the diamond and bridge simultaneously. | ||
uint256 internal eraLegacyBridgeLastDepositTxNumber; | ||
|
||
/// @dev Legacy bridge smart contract that used to hold ERC20 tokens. | ||
IL1ERC20Bridge public override legacyBridge; | ||
|
@@ -110,14 +126,36 @@ | |
/// @dev Initializes a contract bridge for later use. Expected to be used in the proxy | ||
/// @param _owner Address which can change L2 token implementation and upgrade the bridge | ||
/// implementation. The owner is the Governor and separate from the ProxyAdmin from now on, so that the Governor can call the bridge. | ||
function initialize( | ||
address _owner, | ||
uint256 _eraFirstPostUpgradeBatch | ||
) external reentrancyGuardInitializer initializer { | ||
function initialize(address _owner) external reentrancyGuardInitializer initializer { | ||
require(_owner != address(0), "ShB owner 0"); | ||
_transferOwnership(_owner); | ||
} | ||
|
||
/// @dev This sets the first post diamond upgrade batch for era, used to check old eth withdrawals | ||
/// @param _eraPostDiamondUpgradeFirstBatch The first batch number on the zkSync Era Diamond Proxy that was settled after diamond proxy upgrade. | ||
function setEraPostDiamondUpgradeFirstBatch(uint256 _eraPostDiamondUpgradeFirstBatch) external onlyOwner { | ||
require(eraPostDiamondUpgradeFirstBatch == 0, "ShB: eFPUB already set"); | ||
eraPostDiamondUpgradeFirstBatch = _eraPostDiamondUpgradeFirstBatch; | ||
} | ||
|
||
/// @dev This sets the first post upgrade batch for era, used to check old token withdrawals | ||
/// @param _eraPostLegacyBridgeUpgradeFirstBatch The first batch number on the zkSync Era Diamond Proxy that was settled after legacy bridge upgrade. | ||
function setEraPostLegacyBridgeUpgradeFirstBatch(uint256 _eraPostLegacyBridgeUpgradeFirstBatch) external onlyOwner { | ||
require(eraPostLegacyBridgeUpgradeFirstBatch == 0, "ShB: eFPUB already set"); | ||
eraPostLegacyBridgeUpgradeFirstBatch = _eraPostLegacyBridgeUpgradeFirstBatch; | ||
} | ||
|
||
eraFirstPostUpgradeBatch = _eraFirstPostUpgradeBatch; | ||
/// @dev This sets the first post upgrade batch for era, used to check old withdrawals | ||
/// @param _eraLegacyBridgeLastDepositBatch The the zkSync Era batch number that processes the last deposit tx initiated by the legacy bridge | ||
/// @param _eraLegacyBridgeLastDepositTxNumber The tx number in the _eraLegacyBridgeLastDepositBatch of the last deposit tx initiated by the legacy bridge | ||
function setEraLegacyBridgeLastDepositTime( | ||
uint256 _eraLegacyBridgeLastDepositBatch, | ||
uint256 _eraLegacyBridgeLastDepositTxNumber | ||
) external onlyOwner { | ||
require(eraLegacyBridgeLastDepositBatch == 0, "ShB: eLOBDB already set"); | ||
require(eraLegacyBridgeLastDepositTxNumber == 0, "ShB: eLOBDTN already set"); | ||
eraLegacyBridgeLastDepositBatch = _eraLegacyBridgeLastDepositBatch; | ||
eraLegacyBridgeLastDepositTxNumber = _eraLegacyBridgeLastDepositTxNumber; | ||
} | ||
|
||
/// @dev transfer tokens from legacy erc20 bridge or mailbox and set chainBalance as part of migration process | ||
|
@@ -261,7 +299,6 @@ | |
require(address(legacyBridge) == address(0), "ShB: legacy bridge already set"); | ||
require(_legacyBridge != address(0), "ShB: legacy bridge 0"); | ||
legacyBridge = IL1ERC20Bridge(_legacyBridge); | ||
l2BridgeAddress[eraChainId] = address(legacyBridge); | ||
} | ||
|
||
/// @dev Generate a calldata for calling the deposit finalization on the L2 bridge contract | ||
|
@@ -355,7 +392,7 @@ | |
bool notCheckedInLegacyBridgeOrWeCanCheckDeposit; | ||
{ | ||
// Deposits that happened before the upgrade cannot be checked here, they have to be claimed and checked in the legacyBridge | ||
bool weCanCheckDepositHere = !_isEraLegacyWithdrawal(_chainId, _l2BatchNumber); | ||
bool weCanCheckDepositHere = !_isEraLegacyDeposit(_chainId, _l2BatchNumber, _l2TxNumberInBatch); | ||
// Double claims are not possible, as we this check except for legacy bridge withdrawals | ||
// Funds claimed before the update will still be recorded in the legacy bridge | ||
// Note we double check NEW deposits if they are called from the legacy bridge | ||
|
@@ -392,12 +429,46 @@ | |
emit ClaimedFailedDepositSharedBridge(_chainId, _depositSender, _l1Token, _amount); | ||
} | ||
|
||
/// @dev Determines if a withdrawal was initiated on zkSync Era before the upgrade to the Shared Bridge. | ||
/// @dev Determines if an eth withdrawal was initiated on zkSync Era before the upgrade to the Shared Bridge. | ||
/// @param _chainId The chain ID of the transaction to check. | ||
/// @param _l2BatchNumber The L2 batch number for the withdrawal. | ||
/// @return Whether withdrawal was initiated on zkSync Era before Shared Bridge upgrade. | ||
function _isEraLegacyWithdrawal(uint256 _chainId, uint256 _l2BatchNumber) internal view returns (bool) { | ||
return (_chainId == eraChainId) && (_l2BatchNumber < eraFirstPostUpgradeBatch); | ||
/// @return Whether withdrawal was initiated on zkSync Era before diamond proxy upgrade. | ||
function _isEraLegacyEthWithdrawal(uint256 _chainId, uint256 _l2BatchNumber) internal view returns (bool) { | ||
require((_chainId != eraChainId) || eraPostDiamondUpgradeFirstBatch != 0, "ShB: diamondUFB not set for Era"); | ||
return (_chainId == eraChainId) && (_l2BatchNumber < eraPostDiamondUpgradeFirstBatch); | ||
} | ||
|
||
/// @dev Determines if a token withdrawal was initiated on zkSync Era before the upgrade to the Shared Bridge. | ||
/// @param _chainId The chain ID of the transaction to check. | ||
/// @param _l2BatchNumber The L2 batch number for the withdrawal. | ||
/// @return Whether withdrawal was initiated on zkSync Era before Legacy Bridge upgrade. | ||
function _isEraLegacyTokenWithdrawal(uint256 _chainId, uint256 _l2BatchNumber) internal view returns (bool) { | ||
require( | ||
(_chainId != eraChainId) || eraPostLegacyBridgeUpgradeFirstBatch != 0, | ||
"ShB: LegacyUFB not set for Era" | ||
); | ||
return (_chainId == eraChainId) && (_l2BatchNumber < eraPostLegacyBridgeUpgradeFirstBatch); | ||
} | ||
|
||
/// @dev Determines if a deposit was initiated on zkSync Era before the upgrade to the Shared Bridge. | ||
/// @param _chainId The chain ID of the transaction to check. | ||
/// @param _l2BatchNumber The L2 batch number for the deposit where it was processed. | ||
/// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the deposit was processed. | ||
/// @return Whether deposit was initiated on zkSync Era before Shared Bridge upgrade. | ||
function _isEraLegacyDeposit( | ||
uint256 _chainId, | ||
uint256 _l2BatchNumber, | ||
uint256 _l2TxNumberInBatch | ||
) internal view returns (bool) { | ||
require( | ||
(_chainId != eraChainId) || (eraLegacyBridgeLastDepositBatch != 0), | ||
"ShB: last deposit time not set for Era" | ||
); | ||
return | ||
(_chainId == eraChainId) && | ||
(_l2BatchNumber < eraLegacyBridgeLastDepositBatch || | ||
(_l2TxNumberInBatch < eraLegacyBridgeLastDepositTxNumber && | ||
_l2BatchNumber == eraLegacyBridgeLastDepositBatch)); | ||
} | ||
|
||
/// @notice Finalize the withdrawal and release funds | ||
|
@@ -417,7 +488,7 @@ | |
) external override { | ||
// To avoid rewithdrawing txs that have already happened on the legacy bridge. | ||
// Note: new withdraws are all recorded here, so double withdrawing them is not possible. | ||
if (_isEraLegacyWithdrawal(_chainId, _l2BatchNumber)) { | ||
if (_isEraLegacyTokenWithdrawal(_chainId, _l2BatchNumber)) { | ||
require(!legacyBridge.isWithdrawalFinalized(_l2BatchNumber, _l2MessageIndex), "ShB: legacy withdrawal"); | ||
} | ||
_finalizeWithdrawal({ | ||
|
@@ -450,7 +521,7 @@ | |
isWithdrawalFinalized[_chainId][_l2BatchNumber][_l2MessageIndex] = true; | ||
|
||
// Handling special case for withdrawal from zkSync Era initiated before Shared Bridge. | ||
if (_isEraLegacyWithdrawal(_chainId, _l2BatchNumber)) { | ||
if (_isEraLegacyEthWithdrawal(_chainId, _l2BatchNumber)) { | ||
// Checks that the withdrawal wasn't finalized already. | ||
bool alreadyFinalized = IGetters(eraDiamondProxy).isEthWithdrawalFinalized(_l2BatchNumber, _l2MessageIndex); | ||
require(!alreadyFinalized, "Withdrawal is already finalized 2"); | ||
|
@@ -603,13 +674,7 @@ | |
// If the refund recipient is not specified, the refund will be sent to the sender of the transaction. | ||
// Otherwise, the refund will be sent to the specified address. | ||
// If the recipient is a contract on L1, the address alias will be applied. | ||
address refundRecipient = _refundRecipient; | ||
if (_refundRecipient == address(0)) { | ||
// slither-disable-next-line tx-origin | ||
refundRecipient = _prevMsgSender != tx.origin | ||
? AddressAliasHelper.applyL1ToL2Alias(_prevMsgSender) | ||
: _prevMsgSender; | ||
} | ||
address refundRecipient = AddressAliasHelper.actualRefundRecipient(_refundRecipient, _prevMsgSender); | ||
|
||
L2TransactionRequestDirect memory request = L2TransactionRequestDirect({ | ||
chainId: eraChainId, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in the comments: as we this check