mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-08 03:43:56 -05:00
feat: implement L1ETHBridge.finalizeWithdrawal
This commit is contained in:
@@ -12,12 +12,22 @@ import { IMessageService } from "../../messaging/interfaces/IMessageService.sol"
|
||||
import { IETHYieldManager } from "./interfaces/IETHYieldManager.sol";
|
||||
|
||||
contract L1ETHBridge is IL1ETHBridge, Initializable, UUPSUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable, MessageServiceBase {
|
||||
/**
|
||||
* @notice The message status enum.
|
||||
*/
|
||||
enum MessageStatus {
|
||||
Unknown,
|
||||
Requested,
|
||||
Finalized
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice The completed message struct.
|
||||
*/
|
||||
struct CompletedMessage {
|
||||
struct Message {
|
||||
uint256 withdrawalRequestId;
|
||||
bytes32 messageHash;
|
||||
MessageStatus status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,7 +43,7 @@ contract L1ETHBridge is IL1ETHBridge, Initializable, UUPSUpgradeable, OwnableUpg
|
||||
/**
|
||||
* @notice The completed messages.
|
||||
*/
|
||||
mapping(uint256 => CompletedMessage) public completedMessages;
|
||||
mapping(uint256 => Message) public messages;
|
||||
|
||||
/**
|
||||
* @dev Ensures the address is not address(0).
|
||||
@@ -117,10 +127,12 @@ contract L1ETHBridge is IL1ETHBridge, Initializable, UUPSUpgradeable, OwnableUpg
|
||||
uint256 _value,
|
||||
bytes memory _calldata
|
||||
) external nonReentrant onlyMessagingService onlyAuthorizedRemoteSender {
|
||||
emit MessageCompleted(nextCompletedMessageId);
|
||||
bytes32 hash = keccak256(abi.encode(_to, _value, _calldata));
|
||||
uint256 requestId = IETHYieldManager(yieldManager).requestWithdrawal(_value);
|
||||
completedMessages[nextCompletedMessageId] = CompletedMessage(requestId, hash);
|
||||
bytes32 hash = keccak256(abi.encode(_to, _value, _calldata));
|
||||
messages[nextCompletedMessageId] = Message(requestId, hash, MessageStatus.Requested);
|
||||
|
||||
emit BridgingCompleted(nextCompletedMessageId);
|
||||
|
||||
nextCompletedMessageId++;
|
||||
}
|
||||
|
||||
@@ -142,6 +154,35 @@ contract L1ETHBridge is IL1ETHBridge, Initializable, UUPSUpgradeable, OwnableUpg
|
||||
messageService.sendMessage(remoteSender, 0, data);
|
||||
}
|
||||
|
||||
function finalizeWithdrawal(uint256 _messageId, uint256 _hintId, address _to, uint256 _value, bytes memory _calldata) external {
|
||||
Message memory message = messages[_messageId];
|
||||
bytes32 hash = keccak256(abi.encode(_to, _value, _calldata));
|
||||
|
||||
if (message.status != MessageStatus.Requested) {
|
||||
revert L1ETHBridge__MessageAlreadyFinalized();
|
||||
}
|
||||
|
||||
if (message.messageHash != hash) {
|
||||
revert L1ETHBridge__InvalidMessageParameters();
|
||||
}
|
||||
|
||||
message.status = MessageStatus.Finalized;
|
||||
|
||||
uint256 balanceBefore = address(this).balance;
|
||||
IETHYieldManager(yieldManager).claimWithdrawal(message.withdrawalRequestId, _hintId);
|
||||
if (address(this).balance != balanceBefore + _value) {
|
||||
revert L1ETHBridge__WithdrawalClaimFailed();
|
||||
}
|
||||
|
||||
|
||||
(bool success, ) = _to.call{ value: _value }(_calldata);
|
||||
if (!success) {
|
||||
revert L1ETHBridge__ETHTransferFailed();
|
||||
}
|
||||
|
||||
emit MessageFinalized(_messageId);
|
||||
}
|
||||
|
||||
function _authorizeUpgrade(address) internal view override {
|
||||
_checkOwner();
|
||||
}
|
||||
|
||||
@@ -3,4 +3,6 @@ pragma solidity ^0.8.26;
|
||||
|
||||
interface IETHYieldManager {
|
||||
function requestWithdrawal(uint256 _amount) external returns (uint256 requestId);
|
||||
|
||||
function claimWithdrawal(uint256 _requestId, uint256 _hintId) external returns (bool success);
|
||||
}
|
||||
@@ -14,7 +14,19 @@ interface IL1ETHBridge {
|
||||
address indexed setBy
|
||||
);
|
||||
|
||||
event MessageCompleted(
|
||||
/**
|
||||
* @notice Emitted when a bridging is completed.
|
||||
* @param messageId The indexed message id.
|
||||
*/
|
||||
event BridgingCompleted(
|
||||
uint256 indexed messageId
|
||||
);
|
||||
|
||||
/**
|
||||
* @notice Emitted when a message is finalized.
|
||||
* @param messageId The indexed message id.
|
||||
*/
|
||||
event MessageFinalized(
|
||||
uint256 indexed messageId
|
||||
);
|
||||
|
||||
@@ -34,6 +46,9 @@ interface IL1ETHBridge {
|
||||
error L1ETHBridge__ZeroAddressNotAllowed();
|
||||
error L1ETHBridge__ETHTransferFailed();
|
||||
error L1ETHBridge__YieldManagerDepositFailed();
|
||||
error L1ETHBridge__MessageAlreadyFinalized();
|
||||
error L1ETHBridge__InvalidMessageParameters();
|
||||
error L1ETHBridge__WithdrawalClaimFailed();
|
||||
|
||||
function setRemoteSender(address _remoteSender) external;
|
||||
|
||||
|
||||
@@ -149,8 +149,9 @@ contract L1ETHBridgeTest is Test {
|
||||
bridge.completeBridging(user1, 100, "test-data");
|
||||
|
||||
assertEq(bridge.nextCompletedMessageId(), 1);
|
||||
(uint256 withdrawalRequestId, bytes32 hash) = bridge.completedMessages(0);
|
||||
(uint256 withdrawalRequestId, bytes32 hash, L1ETHBridge.MessageStatus status) = bridge.messages(0);
|
||||
assertEq(withdrawalRequestId, 0);
|
||||
assertEq(hash, keccak256(abi.encode(user1, 100, "test-data")));
|
||||
assertEq(uint256(status), uint256(L1ETHBridge.MessageStatus.Requested));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ contract ETHYieldManagerMock {
|
||||
return deposits[deposits.length - 1];
|
||||
}
|
||||
|
||||
function requestWithdrawal(uint256 _amount) external returns (uint256 requestId) {
|
||||
function requestWithdrawal(uint256) external returns (uint256 requestId) {
|
||||
return nextRequestId++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user