// SPDX-License-Identifier: MIT pragma solidity ^0.8.2; import '@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol'; import '@layerzerolabs/solidity-examples/contracts/contracts-upgradable/lzApp/NonblockingLzAppUpgradeable.sol'; abstract contract LZHandlerUpgradeable is Initializable, NonblockingLzAppUpgradeable { using BytesLib for bytes; error INVALID_SENDER(bytes _srcAddress); error INVALID_ENDPOINT(address lzEndpoint); function __LZHandlerUpgradeable_init(address _lzEndpoint) internal onlyInitializing { __Ownable_init_unchained(); __LzAppUpgradeable_init_unchained(_lzEndpoint); } function __LZHandlerUpgradeable_init_unchained() internal onlyInitializing {} //override lzReceive for simpler trustedRemote handling function lzReceive( uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload ) public virtual override { // lzReceive must be called by the endpoint for security if (_msgSender() != address(lzEndpoint)) revert INVALID_ENDPOINT(_msgSender()); _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload); } function estimateSendFee( uint16 _dstChainId, address _fromAddress, address _toAddress, uint _normalizedAmount, bool _useZro, bytes memory _adapterParams ) public view virtual returns (uint nativeFee, uint zroFee) { bytes memory payload = abi.encode(_fromAddress, _toAddress, _normalizedAmount, 0); //fake request id as 0, just for fee estimation, shouldnt make a difference try lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams) returns ( uint nativeFee, uint zroFee ) { return (nativeFee, zroFee); } catch { return (0, 0); } } function _nonblockingLzReceive( uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload ) internal virtual override { (address from, address to, uint normalizedAmount, uint requestId) = abi.decode( _payload, (address, address, uint, uint) ); address sourceAddress; assembly { sourceAddress := mload(add(_srcAddress, 20)) } _lzBridgeFrom(_srcChainId, sourceAddress, _nonce, from, to, normalizedAmount, requestId); } function _lzBridgeTo( bytes memory _payload, uint16 _dstChainId, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams ) internal virtual { _lzSend(_dstChainId, _payload, _refundAddress, _zroPaymentAddress, _adapterParams, msg.value); } function _lzBridgeFrom( uint16 _srcChainId, address _srcAddress, uint64 _nonce, address _from, address _to, uint _normalizedAmount, uint _requestId ) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint[49] private __gap; }