Commit 40214739 authored by Maurelian's avatar Maurelian

feat(ctb): Checked out pre-mcp impl contracts

parent b01ff541
...@@ -12,36 +12,33 @@ import { Constants } from "src/libraries/Constants.sol"; ...@@ -12,36 +12,33 @@ import { Constants } from "src/libraries/Constants.sol";
/// @notice The L1CrossDomainMessenger is a message passing interface between L1 and L2 responsible /// @notice The L1CrossDomainMessenger is a message passing interface between L1 and L2 responsible
/// for sending and receiving data on the L1 side. Users are encouraged to use this /// for sending and receiving data on the L1 side. Users are encouraged to use this
/// interface instead of interacting with lower-level contracts directly. /// interface instead of interacting with lower-level contracts directly.
contract L1CrossDomainMessenger is CrossDomainMessenger, ISemver { contract L1CrossDomainMessenger is CrossDomainMessenger, Semver {
/// @notice Address of the OptimismPortal. The public getter for this /// @notice Address of the OptimismPortal.
/// is legacy and will be removed in the future. Use `portal()` instead. OptimismPortal public immutable PORTAL;
/// @custom:network-specific
/// @custom:legacy
OptimismPortal public PORTAL;
/// @notice Semantic version.
/// @custom:semver 1.7.1
string public constant version = "1.7.1";
/// @custom:semver 1.4.1
/// @notice Constructs the L1CrossDomainMessenger contract. /// @notice Constructs the L1CrossDomainMessenger contract.
constructor() CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER) {
initialize({ _portal: OptimismPortal(payable(0)) });
}
/// @notice Initializes the contract.
/// @param _portal Address of the OptimismPortal contract on this network. /// @param _portal Address of the OptimismPortal contract on this network.
function initialize(OptimismPortal _portal) public reinitializer(Constants.INITIALIZER) { constructor(OptimismPortal _portal)
Semver(1, 4, 1)
CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER)
{
PORTAL = _portal; PORTAL = _portal;
__CrossDomainMessenger_init(); initialize();
} }
/// @notice Getter for the OptimismPortal address. /// @notice Initializes the contract.
function portal() external view returns (address) { function initialize() public initializer {
return address(PORTAL); __CrossDomainMessenger_init();
} }
/// @inheritdoc CrossDomainMessenger /// @inheritdoc CrossDomainMessenger
function _sendMessage(address _to, uint64 _gasLimit, uint256 _value, bytes memory _data) internal override { function _sendMessage(
address _to,
uint64 _gasLimit,
uint256 _value,
bytes memory _data
) internal override {
PORTAL.depositTransaction{ value: _value }(_to, _value, _gasLimit, false, _data); PORTAL.depositTransaction{ value: _value }(_to, _value, _gasLimit, false, _data);
} }
......
...@@ -13,25 +13,19 @@ import { Constants } from "src/libraries/Constants.sol"; ...@@ -13,25 +13,19 @@ import { Constants } from "src/libraries/Constants.sol";
/// @notice The L1 ERC721 bridge is a contract which works together with the L2 ERC721 bridge to /// @notice The L1 ERC721 bridge is a contract which works together with the L2 ERC721 bridge to
/// make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract /// make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract
/// acts as an escrow for ERC721 tokens deposited into L2. /// acts as an escrow for ERC721 tokens deposited into L2.
contract L1ERC721Bridge is ERC721Bridge, ISemver { contract L1ERC721Bridge is ERC721Bridge, Semver {
/// @notice Mapping of L1 token to L2 token to ID to boolean, indicating if the given L1 token /// @notice Mapping of L1 token to L2 token to ID to boolean, indicating if the given L1 token
/// by ID was deposited for a given L2 token. /// by ID was deposited for a given L2 token.
mapping(address => mapping(address => mapping(uint256 => bool))) public deposits; mapping(address => mapping(address => mapping(uint256 => bool))) public deposits;
/// @notice Semantic version. /// @custom:semver 1.1.2
/// @custom:semver 1.4.1 /// @notice Constructs the L1ERC721Bridge contract.
string public constant version = "1.4.1";
/// @notice Constructs the contract.
constructor() ERC721Bridge(Predeploys.L2_ERC721_BRIDGE) {
initialize({ _messenger: CrossDomainMessenger(address(0)) });
}
/// @notice Initializes the contract.
/// @param _messenger Address of the CrossDomainMessenger on this network. /// @param _messenger Address of the CrossDomainMessenger on this network.
function initialize(CrossDomainMessenger _messenger) public reinitializer(Constants.INITIALIZER) { /// @param _otherBridge Address of the ERC721 bridge on the other network.
__ERC721Bridge_init({ _messenger: _messenger }); constructor(address _messenger, address _otherBridge)
} Semver(1, 1, 2)
ERC721Bridge(_messenger, _otherBridge)
{}
/// @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the /// @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the
/// recipient on this domain. /// recipient on this domain.
...@@ -50,10 +44,7 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { ...@@ -50,10 +44,7 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver {
address _to, address _to,
uint256 _tokenId, uint256 _tokenId,
bytes calldata _extraData bytes calldata _extraData
) ) external onlyOtherBridge {
external
onlyOtherBridge
{
require(_localToken != address(this), "L1ERC721Bridge: local token cannot be self"); require(_localToken != address(this), "L1ERC721Bridge: local token cannot be self");
// Checks that the L1/L2 NFT pair has a token ID that is escrowed in the L1 Bridge. // Checks that the L1/L2 NFT pair has a token ID that is escrowed in the L1 Bridge.
...@@ -83,15 +74,18 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { ...@@ -83,15 +74,18 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver {
uint256 _tokenId, uint256 _tokenId,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) internal override {
internal
override
{
require(_remoteToken != address(0), "L1ERC721Bridge: remote token cannot be address(0)"); require(_remoteToken != address(0), "L1ERC721Bridge: remote token cannot be address(0)");
// Construct calldata for _l2Token.finalizeBridgeERC721(_to, _tokenId) // Construct calldata for _l2Token.finalizeBridgeERC721(_to, _tokenId)
bytes memory message = abi.encodeWithSelector( bytes memory message = abi.encodeWithSelector(
L2ERC721Bridge.finalizeBridgeERC721.selector, _remoteToken, _localToken, _from, _to, _tokenId, _extraData L2ERC721Bridge.finalizeBridgeERC721.selector,
_remoteToken,
_localToken,
_from,
_to,
_tokenId,
_extraData
); );
// Lock token into bridge // Lock token into bridge
...@@ -99,7 +93,7 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { ...@@ -99,7 +93,7 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver {
IERC721(_localToken).transferFrom(_from, address(this), _tokenId); IERC721(_localToken).transferFrom(_from, address(this), _tokenId);
// Send calldata into L2 // Send calldata into L2
messenger.sendMessage(OTHER_BRIDGE, message, _minGasLimit); MESSENGER.sendMessage(OTHER_BRIDGE, message, _minGasLimit);
emit ERC721BridgeInitiated(_localToken, _remoteToken, _from, _to, _tokenId, _extraData); emit ERC721BridgeInitiated(_localToken, _remoteToken, _from, _to, _tokenId, _extraData);
} }
} }
...@@ -17,14 +17,19 @@ import { Constants } from "src/libraries/Constants.sol"; ...@@ -17,14 +17,19 @@ import { Constants } from "src/libraries/Constants.sol";
/// NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples /// NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples
/// of some token types that may not be properly supported by this contract include, but are /// of some token types that may not be properly supported by this contract include, but are
/// not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists. /// not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists.
contract L1StandardBridge is StandardBridge, ISemver { contract L1StandardBridge is StandardBridge, Semver {
/// @custom:legacy /// @custom:legacy
/// @notice Emitted whenever a deposit of ETH from L1 into L2 is initiated. /// @notice Emitted whenever a deposit of ETH from L1 into L2 is initiated.
/// @param from Address of the depositor. /// @param from Address of the depositor.
/// @param to Address of the recipient on L2. /// @param to Address of the recipient on L2.
/// @param amount Amount of ETH deposited. /// @param amount Amount of ETH deposited.
/// @param extraData Extra data attached to the deposit. /// @param extraData Extra data attached to the deposit.
event ETHDepositInitiated(address indexed from, address indexed to, uint256 amount, bytes extraData); event ETHDepositInitiated(
address indexed from,
address indexed to,
uint256 amount,
bytes extraData
);
/// @custom:legacy /// @custom:legacy
/// @notice Emitted whenever a withdrawal of ETH from L2 to L1 is finalized. /// @notice Emitted whenever a withdrawal of ETH from L2 to L1 is finalized.
...@@ -32,7 +37,12 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -32,7 +37,12 @@ contract L1StandardBridge is StandardBridge, ISemver {
/// @param to Address of the recipient on L1. /// @param to Address of the recipient on L1.
/// @param amount Amount of ETH withdrawn. /// @param amount Amount of ETH withdrawn.
/// @param extraData Extra data attached to the withdrawal. /// @param extraData Extra data attached to the withdrawal.
event ETHWithdrawalFinalized(address indexed from, address indexed to, uint256 amount, bytes extraData); event ETHWithdrawalFinalized(
address indexed from,
address indexed to,
uint256 amount,
bytes extraData
);
/// @custom:legacy /// @custom:legacy
/// @notice Emitted whenever an ERC20 deposit is initiated. /// @notice Emitted whenever an ERC20 deposit is initiated.
...@@ -68,19 +78,13 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -68,19 +78,13 @@ contract L1StandardBridge is StandardBridge, ISemver {
bytes extraData bytes extraData
); );
/// @notice Semantic version. /// @custom:semver 1.1.1
/// @custom:semver 1.4.1
string public constant version = "1.4.1";
/// @notice Constructs the L1StandardBridge contract. /// @notice Constructs the L1StandardBridge contract.
constructor() StandardBridge(StandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE))) { /// @param _messenger Address of the L1CrossDomainMessenger.
initialize({ _messenger: CrossDomainMessenger(address(0)) }); constructor(address payable _messenger)
} Semver(1, 1, 1)
StandardBridge(_messenger, payable(Predeploys.L2_STANDARD_BRIDGE))
/// @notice Initializer {}
function initialize(CrossDomainMessenger _messenger) public reinitializer(Constants.INITIALIZER) {
__StandardBridge_init({ _messenger: _messenger });
}
/// @notice Allows EOAs to bridge ETH by sending directly to the bridge. /// @notice Allows EOAs to bridge ETH by sending directly to the bridge.
receive() external payable override onlyEOA { receive() external payable override onlyEOA {
...@@ -108,7 +112,11 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -108,7 +112,11 @@ contract L1StandardBridge is StandardBridge, ISemver {
/// @param _extraData Optional data to forward to L2. /// @param _extraData Optional data to forward to L2.
/// Data supplied here will not be used to execute any code on L2 and is /// Data supplied here will not be used to execute any code on L2 and is
/// only emitted as extra data for the convenience of off-chain tooling. /// only emitted as extra data for the convenience of off-chain tooling.
function depositETHTo(address _to, uint32 _minGasLimit, bytes calldata _extraData) external payable { function depositETHTo(
address _to,
uint32 _minGasLimit,
bytes calldata _extraData
) external payable {
_initiateETHDeposit(msg.sender, _to, _minGasLimit, _extraData); _initiateETHDeposit(msg.sender, _to, _minGasLimit, _extraData);
} }
...@@ -127,12 +135,16 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -127,12 +135,16 @@ contract L1StandardBridge is StandardBridge, ISemver {
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) external virtual onlyEOA {
external _initiateERC20Deposit(
virtual _l1Token,
onlyEOA _l2Token,
{ msg.sender,
_initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _minGasLimit, _extraData); msg.sender,
_amount,
_minGasLimit,
_extraData
);
} }
/// @custom:legacy /// @custom:legacy
...@@ -152,11 +164,16 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -152,11 +164,16 @@ contract L1StandardBridge is StandardBridge, ISemver {
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) external virtual {
external _initiateERC20Deposit(
virtual _l1Token,
{ _l2Token,
_initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _minGasLimit, _extraData); msg.sender,
_to,
_amount,
_minGasLimit,
_extraData
);
} }
/// @custom:legacy /// @custom:legacy
...@@ -170,10 +187,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -170,10 +187,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes calldata _extraData bytes calldata _extraData
) ) external payable {
external
payable
{
finalizeBridgeETH(_from, _to, _amount, _extraData); finalizeBridgeETH(_from, _to, _amount, _extraData);
} }
...@@ -192,9 +206,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -192,9 +206,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes calldata _extraData bytes calldata _extraData
) ) external {
external
{
finalizeBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _extraData); finalizeBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _extraData);
} }
...@@ -210,7 +222,12 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -210,7 +222,12 @@ contract L1StandardBridge is StandardBridge, ISemver {
/// @param _to Address of the recipient on L2. /// @param _to Address of the recipient on L2.
/// @param _minGasLimit Minimum gas limit for the deposit message on L2. /// @param _minGasLimit Minimum gas limit for the deposit message on L2.
/// @param _extraData Optional data to forward to L2. /// @param _extraData Optional data to forward to L2.
function _initiateETHDeposit(address _from, address _to, uint32 _minGasLimit, bytes memory _extraData) internal { function _initiateETHDeposit(
address _from,
address _to,
uint32 _minGasLimit,
bytes memory _extraData
) internal {
_initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData); _initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData);
} }
...@@ -230,9 +247,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -230,9 +247,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes memory _extraData bytes memory _extraData
) ) internal {
internal
{
_initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData); _initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData);
} }
...@@ -244,10 +259,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -244,10 +259,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal
override
{
emit ETHDepositInitiated(_from, _to, _amount, _extraData); emit ETHDepositInitiated(_from, _to, _amount, _extraData);
super._emitETHBridgeInitiated(_from, _to, _amount, _extraData); super._emitETHBridgeInitiated(_from, _to, _amount, _extraData);
} }
...@@ -260,10 +272,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -260,10 +272,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal
override
{
emit ETHWithdrawalFinalized(_from, _to, _amount, _extraData); emit ETHWithdrawalFinalized(_from, _to, _amount, _extraData);
super._emitETHBridgeFinalized(_from, _to, _amount, _extraData); super._emitETHBridgeFinalized(_from, _to, _amount, _extraData);
} }
...@@ -278,10 +287,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -278,10 +287,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal
override
{
emit ERC20DepositInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData); emit ERC20DepositInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData); super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
} }
...@@ -296,10 +302,7 @@ contract L1StandardBridge is StandardBridge, ISemver { ...@@ -296,10 +302,7 @@ contract L1StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal
override
{
emit ERC20WithdrawalFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData); emit ERC20WithdrawalFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData); super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
} }
......
...@@ -76,16 +76,16 @@ abstract contract ResourceMetering is Initializable { ...@@ -76,16 +76,16 @@ abstract contract ResourceMetering is Initializable {
uint256 blockDiff = block.number - params.prevBlockNum; uint256 blockDiff = block.number - params.prevBlockNum;
ResourceConfig memory config = _resourceConfig(); ResourceConfig memory config = _resourceConfig();
int256 targetResourceLimit = int256 targetResourceLimit = int256(uint256(config.maxResourceLimit)) /
int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier)); int256(uint256(config.elasticityMultiplier));
if (blockDiff > 0) { if (blockDiff > 0) {
// Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate
// at which deposits can be created and therefore limit the potential for deposits to // at which deposits can be created and therefore limit the potential for deposits to
// spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes. // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes.
int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit; int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit;
int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta) int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta) /
/ (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator))); (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator)));
// Update base fee by adding the base fee delta and clamp the resulting value between // Update base fee by adding the base fee delta and clamp the resulting value between
// min and max. // min and max.
...@@ -155,6 +155,10 @@ abstract contract ResourceMetering is Initializable { ...@@ -155,6 +155,10 @@ abstract contract ResourceMetering is Initializable {
/// child contract. /// child contract.
// solhint-disable-next-line func-name-mixedcase // solhint-disable-next-line func-name-mixedcase
function __ResourceMetering_init() internal onlyInitializing { function __ResourceMetering_init() internal onlyInitializing {
params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) }); params = ResourceParams({
prevBaseFee: 1 gwei,
prevBoughtGas: 0,
prevBlockNum: uint64(block.number)
});
} }
} }
...@@ -19,20 +19,15 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; ...@@ -19,20 +19,15 @@ import { Predeploys } from "src/libraries/Predeploys.sol";
/// bridge ONLY supports ERC721s originally deployed on Ethereum. Users will need to /// bridge ONLY supports ERC721s originally deployed on Ethereum. Users will need to
/// wait for the one-week challenge period to elapse before their Optimism-native NFT /// wait for the one-week challenge period to elapse before their Optimism-native NFT
/// can be refunded on L2. /// can be refunded on L2.
contract L2ERC721Bridge is ERC721Bridge, ISemver { contract L2ERC721Bridge is ERC721Bridge, Semver {
/// @custom:semver 1.4.0 /// @custom:semver 1.1.1
string public constant version = "1.4.0";
/// @notice Constructs the L2ERC721Bridge contract. /// @notice Constructs the L2ERC721Bridge contract.
/// @param _messenger Address of the CrossDomainMessenger on this network.
/// @param _otherBridge Address of the ERC721 bridge on the other network. /// @param _otherBridge Address of the ERC721 bridge on the other network.
constructor(address _otherBridge) ERC721Bridge(_otherBridge) { constructor(address _messenger, address _otherBridge)
initialize(); Semver(1, 1, 1)
} ERC721Bridge(_messenger, _otherBridge)
{}
/// @notice Initializes the contract.
function initialize() public reinitializer(Constants.INITIALIZER) {
__ERC721Bridge_init({ _messenger: CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER) });
}
/// @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the /// @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the
/// recipient on this domain. /// recipient on this domain.
...@@ -51,10 +46,7 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver { ...@@ -51,10 +46,7 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver {
address _to, address _to,
uint256 _tokenId, uint256 _tokenId,
bytes calldata _extraData bytes calldata _extraData
) ) external onlyOtherBridge {
external
onlyOtherBridge
{
require(_localToken != address(this), "L2ERC721Bridge: local token cannot be self"); require(_localToken != address(this), "L2ERC721Bridge: local token cannot be self");
// Note that supportsInterface makes a callback to the _localToken address which is user // Note that supportsInterface makes a callback to the _localToken address which is user
...@@ -86,10 +78,7 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver { ...@@ -86,10 +78,7 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver {
uint256 _tokenId, uint256 _tokenId,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) internal override {
internal
override
{
require(_remoteToken != address(0), "L2ERC721Bridge: remote token cannot be address(0)"); require(_remoteToken != address(0), "L2ERC721Bridge: remote token cannot be address(0)");
// Check that the withdrawal is being initiated by the NFT owner // Check that the withdrawal is being initiated by the NFT owner
...@@ -101,7 +90,10 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver { ...@@ -101,7 +90,10 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver {
// Construct calldata for l1ERC721Bridge.finalizeBridgeERC721(_to, _tokenId) // Construct calldata for l1ERC721Bridge.finalizeBridgeERC721(_to, _tokenId)
// slither-disable-next-line reentrancy-events // slither-disable-next-line reentrancy-events
address remoteToken = IOptimismMintableERC721(_localToken).remoteToken(); address remoteToken = IOptimismMintableERC721(_localToken).remoteToken();
require(remoteToken == _remoteToken, "L2ERC721Bridge: remote token does not match given value"); require(
remoteToken == _remoteToken,
"L2ERC721Bridge: remote token does not match given value"
);
// When a withdrawal is initiated, we burn the withdrawer's NFT to prevent subsequent L2 // When a withdrawal is initiated, we burn the withdrawer's NFT to prevent subsequent L2
// usage // usage
...@@ -109,12 +101,18 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver { ...@@ -109,12 +101,18 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver {
IOptimismMintableERC721(_localToken).burn(_from, _tokenId); IOptimismMintableERC721(_localToken).burn(_from, _tokenId);
bytes memory message = abi.encodeWithSelector( bytes memory message = abi.encodeWithSelector(
L1ERC721Bridge.finalizeBridgeERC721.selector, remoteToken, _localToken, _from, _to, _tokenId, _extraData L1ERC721Bridge.finalizeBridgeERC721.selector,
remoteToken,
_localToken,
_from,
_to,
_tokenId,
_extraData
); );
// Send message to L1 bridge // Send message to L1 bridge
// slither-disable-next-line reentrancy-events // slither-disable-next-line reentrancy-events
messenger.sendMessage(OTHER_BRIDGE, message, _minGasLimit); MESSENGER.sendMessage(OTHER_BRIDGE, message, _minGasLimit);
// slither-disable-next-line reentrancy-events // slither-disable-next-line reentrancy-events
emit ERC721BridgeInitiated(_localToken, remoteToken, _from, _to, _tokenId, _extraData); emit ERC721BridgeInitiated(_localToken, remoteToken, _from, _to, _tokenId, _extraData);
......
...@@ -17,7 +17,7 @@ import { Constants } from "src/libraries/Constants.sol"; ...@@ -17,7 +17,7 @@ import { Constants } from "src/libraries/Constants.sol";
/// NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples /// NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples
/// of some token types that may not be properly supported by this contract include, but are /// of some token types that may not be properly supported by this contract include, but are
/// not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists. /// not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists.
contract L2StandardBridge is StandardBridge, ISemver { contract L2StandardBridge is StandardBridge, Semver {
/// @custom:legacy /// @custom:legacy
/// @notice Emitted whenever a withdrawal from L2 to L1 is initiated. /// @notice Emitted whenever a withdrawal from L2 to L1 is initiated.
/// @param l1Token Address of the token on L1. /// @param l1Token Address of the token on L1.
...@@ -52,24 +52,23 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -52,24 +52,23 @@ contract L2StandardBridge is StandardBridge, ISemver {
bytes extraData bytes extraData
); );
/// @custom:semver 1.4.0 /// @custom:semver 1.1.1
string public constant version = "1.4.0";
/// @notice Constructs the L2StandardBridge contract. /// @notice Constructs the L2StandardBridge contract.
/// @param _otherBridge Address of the L1StandardBridge. /// @param _otherBridge Address of the L1StandardBridge.
constructor(StandardBridge _otherBridge) StandardBridge(_otherBridge) { constructor(address payable _otherBridge)
initialize(); Semver(1, 1, 1)
} StandardBridge(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER), _otherBridge)
{}
/// @notice Initializer
function initialize() public reinitializer(Constants.INITIALIZER) {
__StandardBridge_init({ _messenger: CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER) });
}
/// @notice Allows EOAs to bridge ETH by sending directly to the bridge. /// @notice Allows EOAs to bridge ETH by sending directly to the bridge.
receive() external payable override onlyEOA { receive() external payable override onlyEOA {
_initiateWithdrawal( _initiateWithdrawal(
Predeploys.LEGACY_ERC20_ETH, msg.sender, msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, bytes("") Predeploys.LEGACY_ERC20_ETH,
msg.sender,
msg.sender,
msg.value,
RECEIVE_DEFAULT_GAS_LIMIT,
bytes("")
); );
} }
...@@ -86,12 +85,7 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -86,12 +85,7 @@ contract L2StandardBridge is StandardBridge, ISemver {
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) external payable virtual onlyEOA {
external
payable
virtual
onlyEOA
{
_initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _minGasLimit, _extraData); _initiateWithdrawal(_l2Token, msg.sender, msg.sender, _amount, _minGasLimit, _extraData);
} }
...@@ -114,11 +108,7 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -114,11 +108,7 @@ contract L2StandardBridge is StandardBridge, ISemver {
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) external payable virtual {
external
payable
virtual
{
_initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _minGasLimit, _extraData); _initiateWithdrawal(_l2Token, msg.sender, _to, _amount, _minGasLimit, _extraData);
} }
...@@ -138,11 +128,7 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -138,11 +128,7 @@ contract L2StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes calldata _extraData bytes calldata _extraData
) ) external payable virtual {
external
payable
virtual
{
if (_l1Token == address(0) && _l2Token == Predeploys.LEGACY_ERC20_ETH) { if (_l1Token == address(0) && _l2Token == Predeploys.LEGACY_ERC20_ETH) {
finalizeBridgeETH(_from, _to, _amount, _extraData); finalizeBridgeETH(_from, _to, _amount, _extraData);
} else { } else {
...@@ -172,9 +158,7 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -172,9 +158,7 @@ contract L2StandardBridge is StandardBridge, ISemver {
uint256 _amount, uint256 _amount,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes memory _extraData bytes memory _extraData
) ) internal {
internal
{
if (_l2Token == Predeploys.LEGACY_ERC20_ETH) { if (_l2Token == Predeploys.LEGACY_ERC20_ETH) {
_initiateBridgeETH(_from, _to, _amount, _minGasLimit, _extraData); _initiateBridgeETH(_from, _to, _amount, _minGasLimit, _extraData);
} else { } else {
...@@ -191,11 +175,15 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -191,11 +175,15 @@ contract L2StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal emit WithdrawalInitiated(
override address(0),
{ Predeploys.LEGACY_ERC20_ETH,
emit WithdrawalInitiated(address(0), Predeploys.LEGACY_ERC20_ETH, _from, _to, _amount, _extraData); _from,
_to,
_amount,
_extraData
);
super._emitETHBridgeInitiated(_from, _to, _amount, _extraData); super._emitETHBridgeInitiated(_from, _to, _amount, _extraData);
} }
...@@ -207,11 +195,15 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -207,11 +195,15 @@ contract L2StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal emit DepositFinalized(
override address(0),
{ Predeploys.LEGACY_ERC20_ETH,
emit DepositFinalized(address(0), Predeploys.LEGACY_ERC20_ETH, _from, _to, _amount, _extraData); _from,
_to,
_amount,
_extraData
);
super._emitETHBridgeFinalized(_from, _to, _amount, _extraData); super._emitETHBridgeFinalized(_from, _to, _amount, _extraData);
} }
...@@ -225,10 +217,7 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -225,10 +217,7 @@ contract L2StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal
override
{
emit WithdrawalInitiated(_remoteToken, _localToken, _from, _to, _amount, _extraData); emit WithdrawalInitiated(_remoteToken, _localToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData); super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
} }
...@@ -243,10 +232,7 @@ contract L2StandardBridge is StandardBridge, ISemver { ...@@ -243,10 +232,7 @@ contract L2StandardBridge is StandardBridge, ISemver {
address _to, address _to,
uint256 _amount, uint256 _amount,
bytes memory _extraData bytes memory _extraData
) ) internal override {
internal
override
{
emit DepositFinalized(_remoteToken, _localToken, _from, _to, _amount, _extraData); emit DepositFinalized(_remoteToken, _localToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData); super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
} }
......
...@@ -7,17 +7,15 @@ import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable ...@@ -7,17 +7,15 @@ import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable
/// @title ERC721Bridge /// @title ERC721Bridge
/// @notice ERC721Bridge is a base contract for the L1 and L2 ERC721 bridges. /// @notice ERC721Bridge is a base contract for the L1 and L2 ERC721 bridges.
abstract contract ERC721Bridge is Initializable { abstract contract ERC721Bridge {
/// @notice Messenger contract on this domain. /// @notice Messenger contract on this domain.
/// @custom:network-specific CrossDomainMessenger public immutable MESSENGER;
CrossDomainMessenger public messenger;
/// @notice Address of the bridge on the other network. /// @notice Address of the bridge on the other network.
/// @custom:legacy
address public immutable OTHER_BRIDGE; address public immutable OTHER_BRIDGE;
/// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
uint256[48] private __gap; uint256[49] private __gap;
/// @notice Emitted when an ERC721 bridge to the other network is initiated. /// @notice Emitted when an ERC721 bridge to the other network is initiated.
/// @param localToken Address of the token on this domain. /// @param localToken Address of the token on this domain.
...@@ -54,31 +52,31 @@ abstract contract ERC721Bridge is Initializable { ...@@ -54,31 +52,31 @@ abstract contract ERC721Bridge is Initializable {
/// @notice Ensures that the caller is a cross-chain message from the other bridge. /// @notice Ensures that the caller is a cross-chain message from the other bridge.
modifier onlyOtherBridge() { modifier onlyOtherBridge() {
require( require(
msg.sender == address(messenger) && messenger.xDomainMessageSender() == OTHER_BRIDGE, msg.sender == address(MESSENGER) && MESSENGER.xDomainMessageSender() == OTHER_BRIDGE,
"ERC721Bridge: function can only be called from the other bridge" "ERC721Bridge: function can only be called from the other bridge"
); );
_; _;
} }
/// @notice Constructs the contract. /// @param _messenger Address of the CrossDomainMessenger on this network.
/// @param _otherBridge Address of the ERC721 bridge on the other network. /// @param _otherBridge Address of the ERC721 bridge on the other network.
constructor(address _otherBridge) { constructor(address _messenger, address _otherBridge) {
require(_messenger != address(0), "ERC721Bridge: messenger cannot be address(0)");
require(_otherBridge != address(0), "ERC721Bridge: other bridge cannot be address(0)"); require(_otherBridge != address(0), "ERC721Bridge: other bridge cannot be address(0)");
OTHER_BRIDGE = _otherBridge;
}
// @notice Initializes the contract. MESSENGER = CrossDomainMessenger(_messenger);
/// @param _messenger Address of the CrossDomainMessenger on this network. OTHER_BRIDGE = _otherBridge;
function __ERC721Bridge_init(CrossDomainMessenger _messenger) internal onlyInitializing {
messenger = _messenger;
} }
/// @notice Getter for messenger contract. /// @custom:legacy
function MESSENGER() external view returns (CrossDomainMessenger) { /// @notice Legacy getter for messenger contract.
return messenger; /// @return Messenger contract on this domain.
function messenger() external view returns (CrossDomainMessenger) {
return MESSENGER;
} }
/// @notice Getter for other bridge address. /// @custom:legacy
/// @notice Legacy getter for other bridge address.
/// @return Address of the bridge on the other network. /// @return Address of the bridge on the other network.
function otherBridge() external view returns (address) { function otherBridge() external view returns (address) {
return OTHER_BRIDGE; return OTHER_BRIDGE;
...@@ -106,9 +104,7 @@ abstract contract ERC721Bridge is Initializable { ...@@ -106,9 +104,7 @@ abstract contract ERC721Bridge is Initializable {
uint256 _tokenId, uint256 _tokenId,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) external {
external
{
// Modifier requiring sender to be EOA. This prevents against a user error that would occur // Modifier requiring sender to be EOA. This prevents against a user error that would occur
// if the sender is a smart contract wallet that has a different address on the remote chain // if the sender is a smart contract wallet that has a different address on the remote chain
// (or doesn't have an address on the remote chain at all). The user would fail to receive // (or doesn't have an address on the remote chain at all). The user would fail to receive
...@@ -117,7 +113,15 @@ abstract contract ERC721Bridge is Initializable { ...@@ -117,7 +113,15 @@ abstract contract ERC721Bridge is Initializable {
// care of the user error we want to avoid. // care of the user error we want to avoid.
require(!Address.isContract(msg.sender), "ERC721Bridge: account is not externally owned"); require(!Address.isContract(msg.sender), "ERC721Bridge: account is not externally owned");
_initiateBridgeERC721(_localToken, _remoteToken, msg.sender, msg.sender, _tokenId, _minGasLimit, _extraData); _initiateBridgeERC721(
_localToken,
_remoteToken,
msg.sender,
msg.sender,
_tokenId,
_minGasLimit,
_extraData
);
} }
/// @notice Initiates a bridge of an NFT to some recipient's account on the other chain. Note /// @notice Initiates a bridge of an NFT to some recipient's account on the other chain. Note
...@@ -142,12 +146,18 @@ abstract contract ERC721Bridge is Initializable { ...@@ -142,12 +146,18 @@ abstract contract ERC721Bridge is Initializable {
uint256 _tokenId, uint256 _tokenId,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) external {
external
{
require(_to != address(0), "ERC721Bridge: nft recipient cannot be address(0)"); require(_to != address(0), "ERC721Bridge: nft recipient cannot be address(0)");
_initiateBridgeERC721(_localToken, _remoteToken, msg.sender, _to, _tokenId, _minGasLimit, _extraData); _initiateBridgeERC721(
_localToken,
_remoteToken,
msg.sender,
_to,
_tokenId,
_minGasLimit,
_extraData
);
} }
/// @notice Internal function for initiating a token bridge to the other domain. /// @notice Internal function for initiating a token bridge to the other domain.
...@@ -168,7 +178,5 @@ abstract contract ERC721Bridge is Initializable { ...@@ -168,7 +178,5 @@ abstract contract ERC721Bridge is Initializable {
uint256 _tokenId, uint256 _tokenId,
uint32 _minGasLimit, uint32 _minGasLimit,
bytes calldata _extraData bytes calldata _extraData
) ) internal virtual;
internal
virtual;
} }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
/// @title Semver
/// @notice Semver is a simple contract for managing contract versions.
contract Semver {
/// @notice Contract version number (major).
uint256 private immutable MAJOR_VERSION;
/// @notice Contract version number (minor).
uint256 private immutable MINOR_VERSION;
/// @notice Contract version number (patch).
uint256 private immutable PATCH_VERSION;
/// @param _major Version number (major).
/// @param _minor Version number (minor).
/// @param _patch Version number (patch).
constructor(
uint256 _major,
uint256 _minor,
uint256 _patch
) {
MAJOR_VERSION = _major;
MINOR_VERSION = _minor;
PATCH_VERSION = _patch;
}
/// @notice Returns the full semver contract version.
/// @return Semver contract version as a string.
function version() public view returns (string memory) {
return
string(
abi.encodePacked(
Strings.toString(MAJOR_VERSION),
".",
Strings.toString(MINOR_VERSION),
".",
Strings.toString(PATCH_VERSION)
)
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment