Summary
TempleTeleporter::teleport
does not properly validate the msg.value
sent with the transaction, potentially leading to issues with cross-chain transfers and loss of funds.
Vulnerability Details
In TempleTeleporter::teleport
, the msg.value
is directly passed to the _lzSend
function without any validation:
function teleport(uint32 dstEid, address to, uint256 amount, bytes calldata options)
external
payable
override
returns (MessagingReceipt memory receipt)
{
if (amount == 0) revert CommonEventsAndErrors.ExpectedNonZero();
if (to == address(0)) revert CommonEventsAndErrors.InvalidAddress();
bytes memory _payload = abi.encodePacked(to.addressToBytes32(), amount);
temple.burnFrom(msg.sender, amount);
emit TempleTeleported(dstEid, msg.sender, to, amount);
@> receipt = _lzSend(dstEid, _payload, options, MessagingFee(msg.value, 0), payable(msg.sender));
}
The function uses msg.value
as the native fee for the Layer Zero transfer without checking if it's sufficient to cover the required fees.
Impact
The impact of this vulnerability is twofold:
Users may lose their TEMPLE tokens if they don't provide enough ETH to cover the Layer Zero fees, as the tokens are burned before the cross-chain transfer is attempted.
Users may lose excess ETH if they provide more than necessary for the fees, as there's no mechanism to refund the excess amount.
Tools Used
Manual code review
Recommendations
Implement a fee estimation mechanism using the existing quote
function:
function teleport(uint32 dstEid, address to, uint256 amount, bytes calldata options)
external
payable
override
returns (MessagingReceipt memory receipt)
{
if (amount == 0) revert CommonEventsAndErrors.ExpectedNonZero();
if (to == address(0)) revert CommonEventsAndErrors.InvalidAddress();
bytes memory _payload = abi.encodePacked(to.addressToBytes32(), amount);
+ MessagingFee memory fee = _quote(dstEid, _payload, options, false);
+ if (msg.value < fee.nativeFee) revert InsufficientFee(fee.nativeFee, msg.value);
// Burn tokens
temple.burnFrom(msg.sender, amount);
emit TempleTeleported(dstEid, msg.sender, to, amount);
- receipt = _lzSend(dstEid, _payload, options, MessagingFee(msg.value, 0), payable(msg.sender));
+ receipt = _lzSend(dstEid, _payload, options, MessagingFee(fee.nativeFee, 0), payable(msg.sender));
+ // Refund any excess ETH
+ if (msg.value > fee.nativeFee) {
+ payable(msg.sender).transfer(msg.value - fee.nativeFee);
+ }
}