Skip to content

feat: add setter for extraLzReceiveOption #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/core/DepositLocker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@
/// @notice The address of the DepositExecutor on the destination chain.
address public depositExecutor;

/// @notice The gas limit when calling lzReceive for bridged tokens on the destination chain.
uint128 public extraLzReceiveGasLimit;

/// @notice Mapping of an ERC20 token to its corresponding LayerZero OFT.
/// @dev NOTE: Must implement the IOFT interface.
mapping(ERC20 => IOFT) public tokenToLzV2OFT;
Expand Down Expand Up @@ -301,6 +304,12 @@
*/
event DestinationChainLzEidSet(uint32 dstChainLzEid);

/**
* @notice Emitted when the extra gas limit for receiving bridged tokens on the destination chain is set.
* @param extraLzReceiveGasLimit The new extra gas limit for receiving bridged tokens on the destination chain.
*/
event ExtraLzReceiveGasLimitSet(uint128 extraLzReceiveGasLimit);

/**
* @notice Emitted when the Deposit Executor address is set.
* @param depositExecutor The new address of the Deposit Executor on the destination chain.
Expand Down Expand Up @@ -1237,7 +1246,9 @@
to: _addressToBytes32(depositExecutor),
amountLD: _amountToBridge,
minAmountLD: _amountToBridge,
extraOptions: OptionsBuilder.newOptions().addExecutorLzComposeOption(0, _executorGasLimit, 0),
extraOptions: OptionsBuilder.newOptions()
.addExecutorLzReceiveOption(extraLzReceiveGasLimit, 0)
.addExecutorLzComposeOption(0, _executorGasLimit, 0),
composeMsg: _composeMsg,
oftCmd: ""
});
Expand All @@ -1257,13 +1268,13 @@
WRAPPED_NATIVE_ASSET_TOKEN.withdraw(_amountToBridge);

// Execute the bridge transaction by sending native assets + bridging fee
(messageReceipt, bridgeReceipt) = lzV2OFT.send{ value: messagingFee.nativeFee + _amountToBridge }(sendParam, messagingFee, address(this));

Check warning on line 1271 in src/core/DepositLocker.sol

View workflow job for this annotation

GitHub Actions / Tests (20.x)

Check result of "send" call
} else {
// Approve the lzV2OFT to bridge tokens
_token.safeApprove(address(lzV2OFT), _amountToBridge);

// Execute the bridge transaction
(messageReceipt, bridgeReceipt) = lzV2OFT.send{ value: messagingFee.nativeFee }(sendParam, messagingFee, address(this));

Check warning on line 1277 in src/core/DepositLocker.sol

View workflow job for this annotation

GitHub Actions / Tests (20.x)

Check result of "send" call

Check warning on line 1277 in src/core/DepositLocker.sol

View workflow job for this annotation

GitHub Actions / Tests (20.x)

Avoid multiple calls of "send" method in single transaction
}

// Ensure that all deposits were bridged
Expand Down Expand Up @@ -1330,6 +1341,12 @@
emit DestinationChainLzEidSet(_dstChainLzEid);
}

function setLzReceiveGasLimit(uint128 _gasLimit) external onlyOwner {
extraLzReceiveGasLimit = _gasLimit;
emit ExtraLzReceiveGasLimitSet(_gasLimit);
}


/**
* @notice Sets the DepositExecutor address.
* @dev Only callable by the contract owner.
Expand Down
70 changes: 58 additions & 12 deletions src/libraries/OptionsBuilder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ pragma solidity ^0.8.0;

library SafeCast {
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
require(
value <= type(uint16).max,
"SafeCast: value doesn't fit in 16 bits"
);
return uint16(value);
}
}

library BytesLib {
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
function toUint16(
bytes memory _bytes,
uint256 _start
) internal pure returns (uint16) {
require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
uint16 tempUint;
assembly {
Expand All @@ -21,8 +27,20 @@ library BytesLib {

library ExecutorOptions {
uint8 internal constant WORKER_ID = 1;

uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;
uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;

function encodeLzReceiveOption(
uint128 _gas,
uint128 _value
) internal pure returns (bytes memory) {
return
_value == 0
? abi.encodePacked(_gas)
: abi.encodePacked(_gas, _value);
}

function encodeLzComposeOption(
uint16 _index,
uint128 _gas,
Expand All @@ -41,35 +59,63 @@ library OptionsBuilder {
error InvalidOptionType(uint16 optionType);

modifier onlyType3(bytes memory _options) {
if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));
if (_options.toUint16(0) != TYPE_3)
revert InvalidOptionType(_options.toUint16(0));
_;
}

function newOptions() internal pure returns (bytes memory) {
return abi.encodePacked(TYPE_3);
}

function addExecutorLzReceiveOption(
bytes memory _options,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzReceiveOption(
_gas,
_value
);
return
addExecutorOption(
_options,
ExecutorOptions.OPTION_TYPE_LZRECEIVE,
option
);
}

function addExecutorLzComposeOption(
bytes memory _options,
uint16 _index,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);
bytes memory option = ExecutorOptions.encodeLzComposeOption(
_index,
_gas,
_value
);
return
addExecutorOption(
_options,
ExecutorOptions.OPTION_TYPE_LZCOMPOSE,
option
);
}

function addExecutorOption(
bytes memory _options,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return abi.encodePacked(
_options,
ExecutorOptions.WORKER_ID,
_option.length.toUint16() + 1, // +1 for _optionType
_optionType,
_option
);
return
abi.encodePacked(
_options,
ExecutorOptions.WORKER_ID,
_option.length.toUint16() + 1, // +1 for _optionType
_optionType,
_option
);
}
}
Loading