mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 04:08:01 -05:00
chore: add L1/L2 ETHBridge interfaces and emit events when addresses are updated
This commit is contained in:
@@ -5,18 +5,35 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I
|
||||
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
|
||||
import { IRollup } from "./interfaces/IRollup.sol";
|
||||
import { IL1ETHBridge } from "./interfaces/IL1ETHBridge.sol";
|
||||
import { IL2ETHBridge } from "./interfaces/IL2ETHBridge.sol";
|
||||
import { MessageServiceBase } from "../../messaging/MessageServiceBase.sol";
|
||||
import { IMessageService } from "../../messaging/interfaces/IMessageService.sol";
|
||||
|
||||
contract L1ETHBridge is Initializable, UUPSUpgradeable, OwnableUpgradeable, MessageServiceBase {
|
||||
error L1ETHBridge__ZeroValue();
|
||||
error L1ETHBridge__ZeroAddressNotAllowed();
|
||||
error L1ETHBridge__YieldManagerDepositFailed();
|
||||
|
||||
contract L1ETHBridge is IL1ETHBridge, Initializable, UUPSUpgradeable, OwnableUpgradeable, MessageServiceBase {
|
||||
/**
|
||||
* @notice The yield manager address.
|
||||
*/
|
||||
address public yieldManager;
|
||||
|
||||
/**
|
||||
* @dev Ensures the address is not address(0).
|
||||
* @param _addr Address to check.
|
||||
*/
|
||||
modifier nonZeroAddress(address _addr) {
|
||||
if (_addr == address(0)) revert L1ETHBridge__ZeroAddressNotAllowed();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Ensures the amount is not 0.
|
||||
* @param _amount amount to check.
|
||||
*/
|
||||
modifier nonZeroAmount(uint256 _amount) {
|
||||
if (_amount == 0) revert L1ETHBridge__ZeroValueNotAllowed();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Disables initializers to prevent reinitialization.
|
||||
*/
|
||||
@@ -36,14 +53,11 @@ contract L1ETHBridge is Initializable, UUPSUpgradeable, OwnableUpgradeable, Mess
|
||||
address _messageService,
|
||||
address _remoteSender,
|
||||
address _yieldManager
|
||||
) external initializer {
|
||||
) external initializer nonZeroAddress(_yieldManager) {
|
||||
_transferOwnership(_initialOwner);
|
||||
__MessageServiceBase_init(_messageService);
|
||||
_setRemoteSender(_remoteSender);
|
||||
|
||||
if (_yieldManager == address(0)) {
|
||||
revert L1ETHBridge__ZeroAddressNotAllowed();
|
||||
}
|
||||
yieldManager = _yieldManager;
|
||||
}
|
||||
|
||||
@@ -51,11 +65,8 @@ contract L1ETHBridge is Initializable, UUPSUpgradeable, OwnableUpgradeable, Mess
|
||||
* @notice Sets the message service address.
|
||||
* @param _messageService The new message service address.
|
||||
*/
|
||||
function setMessageService(address _messageService) external onlyOwner {
|
||||
if (_messageService == address(0)) {
|
||||
revert L1ETHBridge__ZeroAddressNotAllowed();
|
||||
}
|
||||
|
||||
function setMessageService(address _messageService) external onlyOwner nonZeroAddress(_messageService) {
|
||||
emit MessageServiceUpdated(_messageService, address(messageService), msg.sender);
|
||||
messageService = IMessageService(_messageService);
|
||||
}
|
||||
|
||||
@@ -71,11 +82,8 @@ contract L1ETHBridge is Initializable, UUPSUpgradeable, OwnableUpgradeable, Mess
|
||||
* @notice Sets the yield manager address.
|
||||
* @param _yieldManager The new yield manager address.
|
||||
*/
|
||||
function setYieldManager(address _yieldManager) external onlyOwner {
|
||||
if (_yieldManager == address(0)) {
|
||||
revert L1ETHBridge__ZeroAddressNotAllowed();
|
||||
}
|
||||
|
||||
function setYieldManager(address _yieldManager) external onlyOwner nonZeroAddress(_yieldManager) {
|
||||
emit YieldManagerUpdated(_yieldManager, yieldManager, msg.sender);
|
||||
yieldManager = _yieldManager;
|
||||
}
|
||||
|
||||
@@ -84,11 +92,10 @@ contract L1ETHBridge is Initializable, UUPSUpgradeable, OwnableUpgradeable, Mess
|
||||
* @param _to The recipient address on the L2.
|
||||
* @param _calldata The calldata to be sent to the L2ETHBridge.
|
||||
*/
|
||||
function bridgeETH(address _to, bytes memory _calldata) external payable {
|
||||
if (msg.value == 0) {
|
||||
revert L1ETHBridge__ZeroValue();
|
||||
}
|
||||
|
||||
function bridgeETH(
|
||||
address _to,
|
||||
bytes memory _calldata
|
||||
) external payable nonZeroAmount(msg.value) nonZeroAddress(_to) {
|
||||
(bool success, ) = yieldManager.call{ value: msg.value }("");
|
||||
if (!success) {
|
||||
revert L1ETHBridge__YieldManagerDepositFailed();
|
||||
|
||||
@@ -5,17 +5,20 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I
|
||||
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
|
||||
import { IL2ETHBridge } from "./interfaces/IL2ETHBridge.sol";
|
||||
import { MessageServiceBase } from "../../messaging/MessageServiceBase.sol";
|
||||
import { IMessageService } from "../../messaging/interfaces/IMessageService.sol";
|
||||
|
||||
contract L2ETHBridge is
|
||||
Initializable,
|
||||
UUPSUpgradeable,
|
||||
OwnableUpgradeable,
|
||||
ReentrancyGuardUpgradeable,
|
||||
MessageServiceBase
|
||||
{
|
||||
error L2ETHBridge__ETHTransferFailed();
|
||||
contract L2ETHBridge is IL2ETHBridge, Initializable, UUPSUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable, MessageServiceBase {
|
||||
|
||||
/**
|
||||
* @dev Ensures the address is not address(0).
|
||||
* @param _addr Address to check.
|
||||
*/
|
||||
modifier nonZeroAddress(address _addr) {
|
||||
if (_addr == address(0)) revert L2ETHBridge__ZeroAddressNotAllowed();
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Disables initializers to prevent reinitialization.
|
||||
@@ -41,7 +44,7 @@ contract L2ETHBridge is
|
||||
* @notice Sets the remote sender address.
|
||||
* @param _remoteSender The L1ETHBridge address.
|
||||
*/
|
||||
function setRemoteSender(address _remoteSender) internal onlyOwner {
|
||||
function setRemoteSender(address _remoteSender) external onlyOwner {
|
||||
_setRemoteSender(_remoteSender);
|
||||
}
|
||||
|
||||
@@ -49,7 +52,9 @@ contract L2ETHBridge is
|
||||
* @notice Sets the L2MessageService address.
|
||||
* @param _messageService The L2 MessageService address.
|
||||
*/
|
||||
function setMessageService(address _messageService) external onlyOwner {
|
||||
function setMessageService(address _messageService) external onlyOwner nonZeroAddress(_messageService) {
|
||||
emit MessageServiceUpdated(_messageService, address(messageService), msg.sender);
|
||||
|
||||
messageService = IMessageService(_messageService);
|
||||
}
|
||||
|
||||
|
||||
40
contracts/src/yield/bridge/interfaces/IL1ETHBridge.sol
Normal file
40
contracts/src/yield/bridge/interfaces/IL1ETHBridge.sol
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
interface IL1ETHBridge {
|
||||
/**
|
||||
* @notice Emitted when the message service address is set.
|
||||
* @param newMessageService The indexed new message service address.
|
||||
* @param oldMessageService The indexed old message service address.
|
||||
* @param setBy The indexed address setting the new message service address.
|
||||
*/
|
||||
event MessageServiceUpdated(
|
||||
address indexed newMessageService,
|
||||
address indexed oldMessageService,
|
||||
address indexed setBy
|
||||
);
|
||||
|
||||
/**
|
||||
* @notice Emitted when the yield manager address is set.
|
||||
* @param newYieldManager The indexed new yield manager address.
|
||||
* @param oldYieldManager The indexed old yield manager address.
|
||||
* @param setBy The indexed address setting the new yield manager address.
|
||||
*/
|
||||
event YieldManagerUpdated(
|
||||
address indexed newYieldManager,
|
||||
address indexed oldYieldManager,
|
||||
address indexed setBy
|
||||
);
|
||||
|
||||
error L1ETHBridge__ZeroValueNotAllowed();
|
||||
error L1ETHBridge__ZeroAddressNotAllowed();
|
||||
error L1ETHBridge__YieldManagerDepositFailed();
|
||||
|
||||
function setRemoteSender(address _remoteSender) external;
|
||||
|
||||
function setMessageService(address _messageService) external;
|
||||
|
||||
function setYieldManager(address _yieldManager) external;
|
||||
|
||||
function bridgeETH(address _to, bytes memory _calldata) external payable;
|
||||
}
|
||||
@@ -2,5 +2,25 @@
|
||||
pragma solidity ^0.8.30;
|
||||
|
||||
interface IL2ETHBridge {
|
||||
/**
|
||||
* @notice Emitted when the message service address is set.
|
||||
* @param newMessageService The indexed new message service address.
|
||||
* @param oldMessageService The indexed old message service address.
|
||||
* @param setBy The indexed address setting the new message service address.
|
||||
*/
|
||||
event MessageServiceUpdated(
|
||||
address indexed newMessageService,
|
||||
address indexed oldMessageService,
|
||||
address indexed setBy
|
||||
);
|
||||
|
||||
error L2ETHBridge__ETHTransferFailed();
|
||||
|
||||
error L2ETHBridge__ZeroAddressNotAllowed();
|
||||
|
||||
function setRemoteSender(address _remoteSender) external;
|
||||
|
||||
function setMessageService(address _messageService) external;
|
||||
|
||||
function completeBridge(address _to, uint256 _value, bytes calldata _calldata) external;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ contract L1ETHBridgeTest is Test {
|
||||
address remoteSender;
|
||||
address user1 = makeAddr("user1");
|
||||
address user2 = makeAddr("user2");
|
||||
address nonAuthorizedSender = makeAddr("nonAuthorizedSender");
|
||||
|
||||
function setUp() public {
|
||||
DeployL1ETHBridge script = new DeployL1ETHBridge();
|
||||
@@ -27,51 +28,74 @@ contract L1ETHBridgeTest is Test {
|
||||
remoteSender = bridge.remoteSender();
|
||||
}
|
||||
|
||||
function test_setYieldManagerRevertsIfNotOwner() public {
|
||||
vm.prank(nonAuthorizedSender);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
bridge.setYieldManager(address(0));
|
||||
}
|
||||
|
||||
function test_setYieldManagerRevertsIfZeroAddress() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert("L1ETHBridge__ZeroAddressNotAllowed()");
|
||||
bridge.setYieldManager(address(0));
|
||||
}
|
||||
|
||||
function test_setYieldManagerSetsYieldManager() public {
|
||||
function test_setYieldManager() public {
|
||||
vm.prank(deployer);
|
||||
address newYieldManager = makeAddr("new-yieldManager");
|
||||
bridge.setYieldManager(newYieldManager);
|
||||
assertEq(bridge.yieldManager(), newYieldManager);
|
||||
}
|
||||
|
||||
function test_setRemoteSenderRevertsIfNotOwner() public {
|
||||
vm.prank(nonAuthorizedSender);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
bridge.setRemoteSender(address(0));
|
||||
}
|
||||
|
||||
function test_setRemoteSenderRevertsIfZeroAddress() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert("ZeroAddressNotAllowed()");
|
||||
bridge.setRemoteSender(address(0));
|
||||
}
|
||||
|
||||
function test_setMessageServiceRevertsIfZeroAddress() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert("L1ETHBridge__ZeroAddressNotAllowed()");
|
||||
bridge.setMessageService(address(0));
|
||||
}
|
||||
|
||||
function test_setMessageServiceSetsMessageService() public {
|
||||
vm.prank(deployer);
|
||||
address newMessageService = makeAddr("new-messageService");
|
||||
bridge.setMessageService(newMessageService);
|
||||
assertEq(address(bridge.messageService()), newMessageService);
|
||||
}
|
||||
|
||||
function test_setRemoteSenderSetsRemoteSender() public {
|
||||
function test_setRemoteSender() public {
|
||||
vm.prank(deployer);
|
||||
address newRemoteSender = makeAddr("new-remoteSender");
|
||||
bridge.setRemoteSender(newRemoteSender);
|
||||
assertEq(bridge.remoteSender(), newRemoteSender);
|
||||
}
|
||||
|
||||
function test_RevertsIfValueIsZero() public {
|
||||
vm.expectRevert("L1ETHBridge__ZeroValue()");
|
||||
bridge.bridgeETH(address(0), "");
|
||||
function test_setMessageServiceRevertsIfNotOwner() public {
|
||||
vm.prank(nonAuthorizedSender);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
bridge.setMessageService(address(0));
|
||||
}
|
||||
|
||||
function test_FundsAreForwardedToYieldManager() public {
|
||||
function test_setMessageServiceRevertsIfZeroAddress() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert("L1ETHBridge__ZeroAddressNotAllowed()");
|
||||
bridge.setMessageService(address(0));
|
||||
}
|
||||
|
||||
function test_setMessageService() public {
|
||||
vm.prank(deployer);
|
||||
address newMessageService = makeAddr("new-messageService");
|
||||
bridge.setMessageService(newMessageService);
|
||||
assertEq(address(bridge.messageService()), newMessageService);
|
||||
}
|
||||
|
||||
function test_BridgeETHRevertsIfValueIsZero() public {
|
||||
vm.expectRevert("L1ETHBridge__ZeroValueNotAllowed()");
|
||||
bridge.bridgeETH(address(1), "");
|
||||
}
|
||||
|
||||
function test_BridgeETHRevertsIfToIsZeroAddress() public {
|
||||
vm.expectRevert("L1ETHBridge__ZeroAddressNotAllowed()");
|
||||
bridge.bridgeETH{ value: 100 }(address(0), "");
|
||||
}
|
||||
|
||||
function test_BridgeETHFundsAreForwardedToYieldManager() public {
|
||||
vm.deal(user1, 100);
|
||||
vm.prank(user1);
|
||||
bridge.bridgeETH{ value: 100 }(user2, "");
|
||||
@@ -83,7 +107,7 @@ contract L1ETHBridgeTest is Test {
|
||||
assertEq(address(yieldManager).balance, 100);
|
||||
}
|
||||
|
||||
function test_MessagesAreSentToL2ETHBridge() public {
|
||||
function test_ETHBridgeMessagesAreSentToL2ETHBridge() public {
|
||||
vm.deal(user1, 100);
|
||||
vm.prank(user1);
|
||||
bridge.bridgeETH{ value: 100 }(user2, "test-message");
|
||||
|
||||
@@ -27,7 +27,45 @@ contract L2ETHBridgeTest is Test {
|
||||
vm.deal(address(bridge), 100e18);
|
||||
}
|
||||
|
||||
function test_RevertsIfMsgSenderIsNotL2MessageService() public {
|
||||
function test_setMessageServiceRevertsIfNotOwner() public {
|
||||
vm.prank(nonAuthorizedSender);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
bridge.setMessageService(address(0));
|
||||
}
|
||||
|
||||
function test_setMessageServiceRevertsIfZeroAddress() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert("L2ETHBridge__ZeroAddressNotAllowed()");
|
||||
bridge.setMessageService(address(0));
|
||||
}
|
||||
|
||||
function test_setMessageService() public {
|
||||
address newMessageService = makeAddr("newMessageService");
|
||||
vm.prank(deployer);
|
||||
bridge.setMessageService(newMessageService);
|
||||
assertEq(address(bridge.messageService()), newMessageService);
|
||||
}
|
||||
|
||||
function test_setRemoteSenderRevertsIfNotOwner() public {
|
||||
vm.prank(nonAuthorizedSender);
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
bridge.setRemoteSender(address(0));
|
||||
}
|
||||
|
||||
function test_setRemoteSenderRevertsIfZeroAddress() public {
|
||||
vm.prank(deployer);
|
||||
vm.expectRevert("ZeroAddressNotAllowed()");
|
||||
bridge.setRemoteSender(address(0));
|
||||
}
|
||||
|
||||
function test_setRemoteSender() public {
|
||||
address newRemoteSender = makeAddr("newRemoteSender");
|
||||
vm.prank(deployer);
|
||||
bridge.setRemoteSender(newRemoteSender);
|
||||
assertEq(bridge.remoteSender(), newRemoteSender);
|
||||
}
|
||||
|
||||
function test_CompleteBridgeRevertsIfMsgSenderIsNotL2MessageService() public {
|
||||
l2MessageService.setOriginalSender(l1ETHBridge);
|
||||
|
||||
vm.prank(nonAuthorizedSender);
|
||||
@@ -35,7 +73,7 @@ contract L2ETHBridgeTest is Test {
|
||||
bridge.completeBridge(l1ETHBridge, 0, "");
|
||||
}
|
||||
|
||||
function test_RevertsIfRemoteSenderIsNotL1ETHBridge() public {
|
||||
function test_CompleteBridgeRevertsIfRemoteSenderIsNotL1ETHBridge() public {
|
||||
l2MessageService.setOriginalSender(nonAuthorizedSender);
|
||||
|
||||
vm.prank(address(l2MessageService));
|
||||
|
||||
Reference in New Issue
Block a user