-
Notifications
You must be signed in to change notification settings - Fork 17
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 #94 from bgd-labs/feat/linea
feat: Add Linea network support
- Loading branch information
Showing
8 changed files
with
604 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.0; | ||
|
||
import './BaseAdapterScript.sol'; | ||
import {LineaAdapter, ILineaAdapter} from '../../src/contracts/adapters/linea/LineaAdapter.sol'; | ||
import {LineaAdapterTestnet} from '../contract_extensions/LineaAdapter.sol'; | ||
|
||
library LineaAdapterDeploymentHelper { | ||
struct LineaAdapterArgs { | ||
BaseAdapterArgs baseArgs; | ||
address lineaMessageService; | ||
} | ||
|
||
function getAdapterCode(LineaAdapterArgs memory lineaArgs) internal pure returns (bytes memory) { | ||
bytes memory creationCode = lineaArgs.baseArgs.isTestnet | ||
? type(LineaAdapterTestnet).creationCode | ||
: type(LineaAdapter).creationCode; | ||
|
||
return | ||
abi.encodePacked( | ||
creationCode, | ||
abi.encode( | ||
ILineaAdapter.LineaParams({ | ||
crossChainController: lineaArgs.baseArgs.crossChainController, | ||
lineaMessageService: lineaArgs.lineaMessageService, | ||
providerGasLimit: lineaArgs.baseArgs.providerGasLimit, | ||
trustedRemotes: lineaArgs.baseArgs.trustedRemotes | ||
}) | ||
) | ||
); | ||
} | ||
} | ||
|
||
abstract contract BaseDeployLineaAdapter is BaseAdapterScript { | ||
function LINEA_MESSAGE_SERVICE() internal view virtual returns (address) { | ||
return address(0); | ||
} | ||
|
||
function PROVIDER_GAS_LIMIT() internal view virtual override returns (uint256) { | ||
return 150_000; | ||
} | ||
|
||
function _getAdapterByteCode( | ||
BaseAdapterArgs memory baseArgs | ||
) internal view override returns (bytes memory) { | ||
require(baseArgs.trustedRemotes.length == 1, 'Linea adapter can only have one remote'); | ||
require(LINEA_MESSAGE_SERVICE() != address(0), 'Linea message service can not be 0'); | ||
|
||
return | ||
LineaAdapterDeploymentHelper.getAdapterCode( | ||
LineaAdapterDeploymentHelper.LineaAdapterArgs({ | ||
baseArgs: baseArgs, | ||
lineaMessageService: LINEA_MESSAGE_SERVICE() | ||
}) | ||
); | ||
} | ||
} |
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,26 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.8; | ||
|
||
import {TestNetChainIds} from 'solidity-utils/contracts/utils/ChainHelpers.sol'; | ||
import {ILineaAdapter, LineaAdapter} from '../../src/contracts/adapters/linea/LineaAdapter.sol'; | ||
|
||
/** | ||
* @title LineaAdapterTestnet | ||
* @author BGD Labs | ||
*/ | ||
contract LineaAdapterTestnet is LineaAdapter { | ||
/** | ||
* @param params object containing the necessary parameters to initialize the contract | ||
*/ | ||
constructor(ILineaAdapter.LineaParams memory params) LineaAdapter(params) {} | ||
|
||
/// @inheritdoc ILineaAdapter | ||
function isDestinationChainIdSupported(uint256 chainId) public pure override returns (bool) { | ||
return chainId == TestNetChainIds.LINEA_SEPOLIA; | ||
} | ||
|
||
/// @inheritdoc ILineaAdapter | ||
function getOriginChainId() public pure override returns (uint256) { | ||
return TestNetChainIds.ETHEREUM_SEPOLIA; | ||
} | ||
} |
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,50 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {IBaseAdapter} from '../IBaseAdapter.sol'; | ||
|
||
/** | ||
* @title ILineaAdapter | ||
* @author BGD Labs | ||
* @notice interface containing the events, objects and method definitions used in the Linea bridge adapter | ||
*/ | ||
interface ILineaAdapter is IBaseAdapter { | ||
/** | ||
* @notice struct used to pass parameters to the Linea constructor | ||
* @param crossChainController address of the cross chain controller that will use this bridge adapter | ||
* @param lineaMessageService Linea entry point address | ||
* @param providerGasLimit base gas limit used by the bridge adapter | ||
* @param trustedRemotes list of remote configurations to set as trusted | ||
*/ | ||
struct LineaParams { | ||
address crossChainController; | ||
address lineaMessageService; | ||
uint256 providerGasLimit; | ||
TrustedRemotesConfig[] trustedRemotes; | ||
} | ||
|
||
/** | ||
* @notice method to get the Linea message service address | ||
* @return address of the Linea message service | ||
*/ | ||
function LINEA_MESSAGE_SERVICE() external view returns (address); | ||
|
||
/** | ||
* @notice method to know if a destination chain is supported by adapter | ||
* @return flag indicating if the destination chain is supported by the adapter | ||
*/ | ||
function isDestinationChainIdSupported(uint256 chainId) external view returns (bool); | ||
|
||
/** | ||
* @notice method called by Linea message service with the bridged message | ||
* @param message bytes containing the bridged information | ||
*/ | ||
function receiveMessage(bytes memory message) external; | ||
|
||
/** | ||
* @notice method to get the origin chain id | ||
* @return id of the chain where the messages originate. | ||
* @dev this method is needed as Optimism does not pass the origin chain | ||
*/ | ||
function getOriginChainId() external view returns (uint256); | ||
} |
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,115 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.0; | ||
|
||
import {IMessageService} from './interfaces/IMessageService.sol'; | ||
import {BaseAdapter} from '../BaseAdapter.sol'; | ||
import {ChainIds} from 'solidity-utils/contracts/utils/ChainHelpers.sol'; | ||
import {Errors} from '../../libs/Errors.sol'; | ||
import {ILineaAdapter, IBaseAdapter} from './ILineaAdapter.sol'; | ||
import {SafeCast} from 'solidity-utils/contracts/oz-common/SafeCast.sol'; | ||
|
||
/** | ||
* @title LineaAdapter | ||
* @author BGD Labs | ||
* @notice Linea bridge adapter. Used to send and receive messages cross chain between Ethereum and Linea | ||
* @dev it uses the eth balance of CrossChainController contract to pay for message bridging as the method to bridge | ||
is called via delegate call | ||
* @dev note that this adapter can only be used for the communication path ETHEREUM -> LINEA | ||
* @dev documentation regarding the Linea bridge can be found here: https://docs.linea.build/get-started/concepts/message-service#technical-reference | ||
*/ | ||
contract LineaAdapter is ILineaAdapter, BaseAdapter { | ||
/// @inheritdoc ILineaAdapter | ||
address public immutable LINEA_MESSAGE_SERVICE; | ||
|
||
uint256 public constant L2_FEE = 0.002 ether; | ||
|
||
/** | ||
* @notice only calls from the set message service are accepted. | ||
*/ | ||
modifier onlyLineaMessageService() { | ||
require(msg.sender == address(LINEA_MESSAGE_SERVICE), Errors.CALLER_NOT_LINEA_MESSAGE_SERVICE); | ||
_; | ||
} | ||
|
||
/** | ||
* @param params object containing the necessary parameters to initialize the contract | ||
*/ | ||
constructor( | ||
LineaParams memory params | ||
) | ||
BaseAdapter( | ||
params.crossChainController, | ||
params.providerGasLimit, | ||
'Linea native adapter', | ||
params.trustedRemotes | ||
) | ||
{ | ||
require( | ||
params.lineaMessageService != address(0), | ||
Errors.LINEA_MESSAGE_SERVICE_CANT_BE_ADDRESS_0 | ||
); | ||
LINEA_MESSAGE_SERVICE = params.lineaMessageService; | ||
} | ||
|
||
/// @inheritdoc IBaseAdapter | ||
function forwardMessage( | ||
address receiver, | ||
uint256, | ||
uint256 destinationChainId, | ||
bytes calldata message | ||
) external virtual returns (address, uint256) { | ||
require( | ||
isDestinationChainIdSupported(destinationChainId), | ||
Errors.DESTINATION_CHAIN_ID_NOT_SUPPORTED | ||
); | ||
require(receiver != address(0), Errors.RECEIVER_NOT_SET); | ||
|
||
|
||
require(address(this).balance >= L2_FEE, Errors.NOT_ENOUGH_VALUE_TO_PAY_BRIDGE_FEES); | ||
|
||
// @dev we set _fee to hardcoded L2_FEE to overpay to ensure automatic claiming. If by some case it is not enough then | ||
// we will do the claim manually. Until an automated way of getting the price is implemented by Linea | ||
IMessageService(LINEA_MESSAGE_SERVICE).sendMessage{value: L2_FEE}( | ||
receiver, | ||
L2_FEE, | ||
abi.encodeWithSelector(ILineaAdapter.receiveMessage.selector, message) | ||
); | ||
return (LINEA_MESSAGE_SERVICE, 0); | ||
} | ||
|
||
/// @inheritdoc ILineaAdapter | ||
function receiveMessage(bytes calldata message) external onlyLineaMessageService { | ||
uint256 originChainId = getOriginChainId(); | ||
address srcAddress = IMessageService(LINEA_MESSAGE_SERVICE).sender(); | ||
require( | ||
_trustedRemotes[originChainId] == srcAddress && srcAddress != address(0), | ||
Errors.REMOTE_NOT_TRUSTED | ||
); | ||
|
||
_registerReceivedMessage(message, originChainId); | ||
} | ||
|
||
/// @inheritdoc ILineaAdapter | ||
function getOriginChainId() public pure virtual returns (uint256) { | ||
return ChainIds.ETHEREUM; | ||
} | ||
|
||
/// @inheritdoc ILineaAdapter | ||
function isDestinationChainIdSupported(uint256 chainId) public pure virtual returns (bool) { | ||
return chainId == ChainIds.LINEA; | ||
} | ||
|
||
/// @inheritdoc IBaseAdapter | ||
function nativeToInfraChainId( | ||
uint256 nativeChainId | ||
) public pure override(BaseAdapter, IBaseAdapter) returns (uint256) { | ||
return nativeChainId; | ||
} | ||
|
||
/// @inheritdoc IBaseAdapter | ||
function infraToNativeChainId( | ||
uint256 infraChainId | ||
) public pure override(BaseAdapter, IBaseAdapter) returns (uint256) { | ||
return infraChainId; | ||
} | ||
} |
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,26 @@ | ||
# Manual Message Claiming | ||
|
||
To manually claim a message sent from origin (Ethereum) on the Linea network follow these steps: | ||
|
||
1. Get the tx hash where the message was sent on the origin network (Ethereum). This is to get all the information | ||
needed on the following steps. Once you have the tx hash, go to the block explorer, input the tx hash, and then go to events. | ||
Once you are on the events page of the tx, locate the event `MessageSent` | ||
2. Go to the online event decode page: https://tools.deth.net/event-decoder and input the event topics from step 1, and the data. | ||
Add this code (event abi) to the ABI text box: | ||
``` | ||
event MessageSent( | ||
address indexed _from, | ||
address indexed _to, | ||
uint256 _fee, | ||
uint256 _value, | ||
uint256 _nonce, | ||
bytes _calldata, | ||
bytes32 indexed _messageHash | ||
); | ||
``` | ||
3. Go to the Linea block explorer: https://lineascan.build/ and add the Linea MessageService contract: | ||
- mainnet: [0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec](https://lineascan.build/address/0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec#writeProxyContract) | ||
- sepolia: [0x971e727e956690b9957be6d51Ec16E73AcAC83A7](https://sepolia.lineascan.build/address/0x971e727e956690b9957be6d51Ec16E73AcAC83A7#writeProxyContract) | ||
Once there go to write as proxy contract, and fill the information from step 2 to the method `claimMessage` and execute the tx. | ||
Take into account that the topics, calldata and nonce must be in Hex format. | ||
|
20 changes: 20 additions & 0 deletions
20
src/contracts/adapters/linea/interfaces/IMessageService.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,20 @@ | ||
// SPDX-License-Identifier: MIT | ||
// Modified from: https://docs.linea.build/get-started/concepts/message-service#interface-imessageservicesol | ||
pragma solidity ^0.8.0; | ||
|
||
interface IMessageService { | ||
/** | ||
* @notice Sends a message for transporting from the given chain. | ||
* @dev This function should be called with a msg.value = _value + _fee. The fee will be paid on the destination chain. | ||
* @param _to The destination address on the destination chain. | ||
* @param _fee The message service fee on the origin chain. | ||
* @param _calldata The calldata used by the destination message service to call the destination contract. | ||
*/ | ||
function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable; | ||
|
||
/** | ||
* @notice Returns the original sender of the message on the origin layer. | ||
* @return The original sender of the message on the origin layer. | ||
*/ | ||
function sender() external view returns (address); | ||
} |
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
Oops, something went wrong.