-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #920 from matter-labs/kl/h01-2gw
Kl/h01 2gw
- Loading branch information
Showing
7 changed files
with
181 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; | |
import {BridgedStandardERC20} from "../BridgedStandardERC20.sol"; | ||
import {BridgeHelper} from "../BridgeHelper.sol"; | ||
|
||
import {EmptyDeposit, Unauthorized, TokensWithFeesNotSupported, TokenNotSupported, NonEmptyMsgValue, ValueMismatch, AddressMismatch, AssetIdMismatch, AmountMustBeGreaterThanZero, ZeroAddress} from "../../common/L1ContractErrors.sol"; | ||
import {EmptyDeposit, Unauthorized, TokensWithFeesNotSupported, TokenNotSupported, NonEmptyMsgValue, ValueMismatch, AddressMismatch, AssetIdMismatch, AmountMustBeGreaterThanZero, ZeroAddress, DeployingBridgedTokenForNativeToken} from "../../common/L1ContractErrors.sol"; | ||
|
||
/// @author Matter Labs | ||
/// @custom:security-contact [email protected] | ||
|
@@ -132,7 +132,7 @@ abstract contract NativeTokenVault is INativeTokenVault, IAssetHandler, Ownable2 | |
(, receiver, originToken, amount, erc20Data) = DataEncoding.decodeBridgeMintData(_data); | ||
|
||
if (token == address(0)) { | ||
token = _ensureTokenDeployed(_originChainId, _assetId, originToken, erc20Data); | ||
token = _ensureAndSaveTokenDeployed(_assetId, originToken, erc20Data); | ||
} | ||
_handleChainBalanceDecrease(_originChainId, _assetId, amount, false); | ||
IBridgedStandardToken(token).bridgeMint(receiver, amount); | ||
|
@@ -354,43 +354,59 @@ abstract contract NativeTokenVault is INativeTokenVault, IAssetHandler, Ownable2 | |
TOKEN DEPLOYER FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
|
||
function _ensureTokenDeployed( | ||
uint256 _originChainId, | ||
function _ensureAndSaveTokenDeployed( | ||
bytes32 _assetId, | ||
address _originToken, | ||
bytes memory _erc20Data | ||
) internal virtual returns (address expectedToken) { | ||
expectedToken = _assetIdCheck(_originChainId, _assetId, _originToken); | ||
_ensureTokenDeployedInner({ | ||
_originChainId: _originChainId, | ||
uint256 tokenOriginChainId; | ||
(expectedToken, tokenOriginChainId) = _calculateExpectedTokenAddress(_originToken, _erc20Data); | ||
_ensureAndSaveTokenDeployedInner({ | ||
_tokenOriginChainId: tokenOriginChainId, | ||
_assetId: _assetId, | ||
_originToken: _originToken, | ||
_erc20Data: _erc20Data, | ||
_expectedToken: expectedToken | ||
}); | ||
} | ||
|
||
function _assetIdCheck( | ||
uint256 _originChainId, | ||
bytes32 _assetId, | ||
address _originToken | ||
) internal view returns (address expectedToken) { | ||
expectedToken = calculateCreate2TokenAddress(_originChainId, _originToken); | ||
bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(_originChainId, _originToken); | ||
/// @notice Calculates the bridged token address corresponding to native token counterpart. | ||
function _calculateExpectedTokenAddress( | ||
address _originToken, | ||
bytes memory _erc20Data | ||
) internal view returns (address expectedToken, uint256 tokenOriginChainId) { | ||
/// @dev calling externally to convert from memory to calldata | ||
tokenOriginChainId = this.tokenDataOriginChainId(_erc20Data); | ||
expectedToken = calculateCreate2TokenAddress(tokenOriginChainId, _originToken); | ||
} | ||
|
||
/// @notice Returns the origin chain id from the token data. | ||
function tokenDataOriginChainId(bytes calldata _erc20Data) public view returns (uint256 tokenOriginChainId) { | ||
(tokenOriginChainId, , , ) = DataEncoding.decodeTokenData(_erc20Data); | ||
if (tokenOriginChainId == 0) { | ||
tokenOriginChainId = L1_CHAIN_ID; | ||
} | ||
} | ||
|
||
/// @notice Checks that the assetId is correct for the origin token and chain. | ||
function _assetIdCheck(uint256 _tokenOriginChainId, bytes32 _assetId, address _originToken) internal view { | ||
bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(_tokenOriginChainId, _originToken); | ||
if (_assetId != expectedAssetId) { | ||
// Make sure that a NativeTokenVault sent the message | ||
revert AssetIdMismatch(_assetId, expectedAssetId); | ||
} | ||
} | ||
|
||
function _ensureTokenDeployedInner( | ||
uint256 _originChainId, | ||
function _ensureAndSaveTokenDeployedInner( | ||
uint256 _tokenOriginChainId, | ||
bytes32 _assetId, | ||
address _originToken, | ||
bytes memory _erc20Data, | ||
address _expectedToken | ||
) internal { | ||
address deployedToken = _deployBridgedToken(_originChainId, _originToken, _erc20Data); | ||
_assetIdCheck(_tokenOriginChainId, _assetId, _originToken); | ||
|
||
address deployedToken = _deployBridgedToken(_tokenOriginChainId, _assetId, _originToken, _erc20Data); | ||
if (deployedToken != _expectedToken) { | ||
revert AddressMismatch(_expectedToken, deployedToken); | ||
} | ||
|
@@ -399,28 +415,34 @@ abstract contract NativeTokenVault is INativeTokenVault, IAssetHandler, Ownable2 | |
} | ||
|
||
/// @notice Calculates the bridged token address corresponding to native token counterpart. | ||
/// @param _tokenOriginChainId The chain id of the origin token. | ||
/// @param _bridgeToken The address of native token. | ||
/// @return The address of bridged token. | ||
function calculateCreate2TokenAddress( | ||
uint256 _originChainId, | ||
uint256 _tokenOriginChainId, | ||
address _bridgeToken | ||
) public view virtual override returns (address); | ||
|
||
/// @notice Deploys and initializes the bridged token for the native counterpart. | ||
/// @param _tokenOriginChainId The chain id of the origin token. | ||
/// @param _originToken The address of origin token. | ||
/// @param _erc20Data The ERC20 metadata of the token deployed. | ||
/// @return The address of the beacon proxy (bridged token). | ||
function _deployBridgedToken( | ||
uint256 _originChainId, | ||
uint256 _tokenOriginChainId, | ||
bytes32 _assetId, | ||
address _originToken, | ||
bytes memory _erc20Data | ||
) internal returns (address) { | ||
bytes32 salt = _getCreate2Salt(_originChainId, _originToken); | ||
if (_tokenOriginChainId == block.chainid) { | ||
revert DeployingBridgedTokenForNativeToken(); | ||
} | ||
bytes32 salt = _getCreate2Salt(_tokenOriginChainId, _originToken); | ||
|
||
BeaconProxy l2Token = _deployBeaconProxy(salt, _tokenOriginChainId); | ||
BridgedStandardERC20(address(l2Token)).bridgeInitialize(_originToken, _erc20Data); | ||
|
||
BeaconProxy l2Token = _deployBeaconProxy(salt); | ||
uint256 tokenOriginChainId = BridgedStandardERC20(address(l2Token)).bridgeInitialize(_originToken, _erc20Data); | ||
tokenOriginChainId = tokenOriginChainId == 0 ? L1_CHAIN_ID : tokenOriginChainId; | ||
originChainId[DataEncoding.encodeNTVAssetId(tokenOriginChainId, _originToken)] = tokenOriginChainId; | ||
originChainId[_assetId] = _tokenOriginChainId; | ||
return address(l2Token); | ||
} | ||
|
||
|
@@ -436,7 +458,10 @@ abstract contract NativeTokenVault is INativeTokenVault, IAssetHandler, Ownable2 | |
/// for the code of the proxy. | ||
/// @param _salt The salt used for beacon proxy deployment of the bridged token (we pass the native token address). | ||
/// @return proxy The beacon proxy, i.e. bridged token. | ||
function _deployBeaconProxy(bytes32 _salt) internal virtual returns (BeaconProxy proxy); | ||
function _deployBeaconProxy( | ||
bytes32 _salt, | ||
uint256 _tokenOriginChainId | ||
) internal virtual returns (BeaconProxy proxy); | ||
|
||
/*////////////////////////////////////////////////////////////// | ||
PAUSE | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
l1-contracts/contracts/dev-contracts/test/L2NativeTokenVaultDev.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity 0.8.24; | ||
|
||
import {BeaconProxy} from "@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol"; | ||
import {Create2} from "@openzeppelin/contracts-v4/utils/Create2.sol"; | ||
import {IBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/IBeacon.sol"; | ||
import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; | ||
|
||
import {INativeTokenVault} from "contracts/bridge/ntv/INativeTokenVault.sol"; | ||
import {NativeTokenVault} from "contracts/bridge/ntv/NativeTokenVault.sol"; | ||
import {L2NativeTokenVault} from "contracts/bridge/ntv/L2NativeTokenVault.sol"; | ||
import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; | ||
|
||
/// @author Matter Labs | ||
/// @notice This is used for fast debugging of the L2NTV by running it in L1 context, i.e. normal foundry instead of foundry --zksync. | ||
contract L2NativeTokenVaultDev is L2NativeTokenVault { | ||
constructor( | ||
uint256 _l1ChainId, | ||
address _aliasedOwner, | ||
bytes32 _l2TokenProxyBytecodeHash, | ||
address _legacySharedBridge, | ||
address _bridgedTokenBeacon, | ||
bool _contractsDeployedAlready, | ||
address _wethToken, | ||
bytes32 _baseTokenAssetId | ||
) | ||
L2NativeTokenVault( | ||
_l1ChainId, | ||
_aliasedOwner, | ||
_l2TokenProxyBytecodeHash, | ||
_legacySharedBridge, | ||
_bridgedTokenBeacon, | ||
_contractsDeployedAlready, | ||
_wethToken, | ||
_baseTokenAssetId | ||
) | ||
{} | ||
|
||
/// @notice copied from L1NTV for L1 compilation | ||
function calculateCreate2TokenAddress( | ||
uint256 _originChainId, | ||
address _l1Token | ||
) public view override(L2NativeTokenVault) returns (address) { | ||
bytes32 salt = _getCreate2Salt(_originChainId, _l1Token); | ||
return | ||
Create2.computeAddress( | ||
salt, | ||
keccak256(abi.encodePacked(type(BeaconProxy).creationCode, abi.encode(bridgedTokenBeacon, ""))) | ||
); | ||
} | ||
|
||
function deployBridgedStandardERC20(address _owner) external { | ||
_transferOwnership(_owner); | ||
|
||
address l2StandardToken = address(new BridgedStandardERC20{salt: bytes32(0)}()); | ||
|
||
UpgradeableBeacon tokenBeacon = new UpgradeableBeacon{salt: bytes32(0)}(l2StandardToken); | ||
|
||
tokenBeacon.transferOwnership(owner()); | ||
bridgedTokenBeacon = IBeacon(address(tokenBeacon)); | ||
emit L2TokenBeaconUpdated(address(bridgedTokenBeacon), l2TokenProxyBytecodeHash); | ||
} | ||
|
||
function test() external pure { | ||
// test | ||
} | ||
|
||
function _deployBeaconProxy(bytes32 _salt, uint256) internal virtual override returns (BeaconProxy proxy) { | ||
// Use CREATE2 to deploy the BeaconProxy | ||
address proxyAddress = Create2.deploy( | ||
0, | ||
_salt, | ||
abi.encodePacked(type(BeaconProxy).creationCode, abi.encode(bridgedTokenBeacon, "")) | ||
); | ||
return BeaconProxy(payable(proxyAddress)); | ||
} | ||
} |
Oops, something went wrong.