L1SenderV2
Introduction
The L1SenderV2
contract serves as a critical component in the cross-chain infrastructure of the protocol. Its primary responsibility is to transfer both reward data and yield assets from Ethereum (L1) to Arbitrum (L2), ensuring that users receive accurate MOR token rewards and that the protocol’s yield is available for conversion and distribution on L2.
The contract automatically receives deposit tokens from the Distributor
contract. These tokens represent the yield generated by various DepositPools
and may come in different ERC-20 formats depending on the underlying staking strategy. To unify these assets for bridging, the L1SenderV2
integrates with Uniswap v3, enabling it to swap the received tokens into wstETH. Once converted, the resulting wstETH is sent through the Arbitrum Bridge to the L2TokenReceiverV2
contract on Arbitrum, ensuring the protocol’s yield is properly transferred and made available for liquidity and reward mechanisms on L2.
Key Responsibilities
Cross-chain reward messaging via LayerZero:
The contract communicates with the
L2MessageReceiver
on Arbitrum using LayerZero.It packages the user’s reward data (including recipient address and reward amount) and sends it securely across chains.
This action is triggered by the
DepositPool
contract after calculating a user’s rewards.On arrival to L2, the message is decoded, and MOR tokens are minted to the user.
Bridging stETH yield via Arbitrum Bridge:
The contract manages the bridging of yield generated from stETH held by the Morpheus protocol.
It wraps stETH into wstETH and uses Arbitrum Bridge to transfer tokens to the
L2TokenReceiver
contract.
Token configuration management:
The contract stores configuration data for both deposit and reward tokens:
Deposit token: the wrapped stETH token to be bridged.
Reward token: LayerZero configuration for sending mint instructions.
It handles dynamic updates to these configurations, allowing the protocol to change tokens or gateways without redeploying the contract.
Automated deposit handling:
Receives various yield tokens directly from the
Distributor
contract.Uniswap V3 integration for token conversion:
Swaps received tokens into wstETH before bridging to L2.
Storage
stETH
The address of the original deposit token (e.g., stETH) before it is wrapped for cross-chain transfer.
address public stETH;
distributor
The address of the Distributor
contract.
address public distributor;
arbitrumBridgeConfig
Configuration details for bridging the stETH token via Arbitrum Bridge.
ArbitrumBridgeConfig public arbitrumBridgeConfig;
struct ArbitrumBridgeConfig {
address token;
address gateway;
address receiver;
}
token
The address of wstETH.
gateway
The address of token's gateway, L1GatewayRouter
receiver
The L2MessageReceiver
address.
layerZeroConfig
Configuration for the LayerZero cross-chain messaging.
LayerZeroConfig public layerZeroConfig;
struct LayerZeroConfig {
address gateway;
address receiver;
uint16 receiverChainId;
address zroPaymentAddress;
bytes adapterParams;
}
gateway
The LayerZero EnpointV1
address.
receiver
The L2MessageReceiver
address.
receiverChainId
The receiver chain ID, from the LZ doc.
zroPaymentAddress
The LayerZero ZRO payment address for gas fees.
adapterParams
LayerZero adapter parameters used to customize messaging behavior.
Write functions for the contract owner
L1SenderV2__init
Initializes the contract. This is a one-time setup function, used during deployment via proxies.
function L1SenderV2__init() external initializer
setStETh
Allows the contract owner to set or update the address of the stETH token.
function setStETh(address value_) external onlyOwner
value_
The stETH token address
setDistributor
Allows the contract owner to set or update the address of the Distributor
contract.
function setDistributor(address value_) public onlyOwner
value_
The Distributor
contract address
setUniswapSwapRouter
Allows the contract owner to set the Uniswap v3 SwapRouter
contract address.
function setUniswapSwapRouter(address value_) external onlyOwner
value_
The SwapRouter
contract address
setLayerZeroConfig
Allows the contract owner to update the LayerZero MOR token configuration used for cross-chain messaging.
function setLayerZeroConfig(
LayerZeroConfig calldata layerZeroConfig_
) external onlyOwner
layerZeroConfig_
Configuration for the LayerZero cross-chain messaging.
setArbitrumBridgeConfig
Allows the contract owner to update the Arbitrum Bridge configuration.
function setArbitrumBridgeConfig(
ArbitrumBridgeConfig calldata newConfig_
) external onlyOwner
newConfig_
Configuration details for bridging the stETH token.
sendWstETH
Transfers tokens on the contract balance (e.g., stETH and wstETH) from L1 to L2 using the Arbitrum Bridge.
function sendWstETH(
uint256 gasLimit_,
uint256 maxFeePerGas_,
uint256 maxSubmissionCost_
) external payable onlyOwner returns (bytes memory)
gasLimit_
Gas limit for the L2 execution.
maxFeePerGas_
Max fee for L2 execution.
maxSubmissionCost_
Base submission cost for the retryable ticket.
swapExactInputMultihop
Allows the contract owner to swap deposit asset to the wstETH via Uniswap v3. Support multihop swaps (e.g. USDC/wETH, wETH/wstETH).
function swapExactInputMultihop(
address[] calldata tokens_,
uint24[] calldata poolsFee_,
uint256 amountIn_,
uint256 amountOutMinimum_,
uint256 deadline_
) external onlyOwner returns (uint256)
tokens_
Tokens addresses. [USDC, wETH, wstETH]
poolsFee_
Uniswap v3 pool fee (e.g., 3000 = 0.3%).
amountIn_
The input token amount to swap. See the token decimals for the precision.
amountOutMinimum_
The minimal tokens amount at the end of swap (wstETH). See the token decimals for the precision.
deadline_
Expiry timestamp in seconds for the transaction.
Write functions for the Distributor contract
sendMintMessage
Sends a cross-chain message via LayerZero to L2, instructing minting of MOR tokens to the user.
function sendMintMessage(
address user_,
uint256 amount_,
address refundTo_
) external payable
user_
Recipient address on L2.
amount_
Amount of tokens to mint. Wei.
refundTo_
Address that receives any unspent msg.value.
Read functions
supportsInterface
Used for interface detection (ERC165). Returns true if the contract supports a specific interfaceId_
. Supports IL1SenderV2
, IERC165
.
function supportsInterface(bytes4 interfaceId_) external pure returns (bool)
version
Returns the current version of the contract.
function version() external pure returns (uint256)
Last updated
Was this helpful?