TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: low
Invalid

`TempleGold` layerzero channels can be blocked if insufficient gas is sent by the user to bridge their tokens

## Summary
`TempleGold` layerzero channel can be blocked if the user bridged their tokens with an insufficient gas to execute bridging on the destination chain.
## Vulnerability Details
- Users can bridge their `$TGLD` tokens between chains via `TempleGold.send()` function, where different checks are made before bridging these tokens:
1. Checking that the `_sendParam.composeMsg` is empty as composing messages to be executed over chains are not allowed by the protocol.
2. Checking that the sender address on the source chain is the receiver address on the destination chain (by reverting the txn if `msg.sender != _sendParam.to.bytes32ToAddress()`).
3. Checking that the bridged amount is >= minimum required amount on the destination chain after removing the dust (this is done via `_debit()`), and then the bridged `$TGLD` tokens are burnt from the user on the source chain to be minted on the destination chain.
and after these checks; a bridging message is built based on the `_sendParam` & `amountReceivedLD`, then `_lzSend()` is called to send the bridged message via the authorized layerzero endpoint.
- LayerZero endpoint requires a sufficient amount of gas to be sent with the bridged message to execute the txn on the destination chain, and if an insufficient gas is sent; the txn will revert on the `TempleGold` contract on the destination chain with an out-of-gas error, and this is [catched and stored](https://github.com/LayerZero-Labs/LayerZero/blob/a1fb11a3b9c0ac449291816e71eacede4e36613e/contracts/Endpoint.sol#L120C5-L124C10) by the layerzero endpoint on the destination chain (the payload is stored in `storedPayload[_srcChainId][_srcAddress]`):
```javascript
//@note : LayerZero/contracts/Endpoint.sol
// https://github.com/LayerZero-Labs/LayerZero/blob/a1fb11a3b9c0ac449291816e71eacede4e36613e/contracts/Endpoint.sol#L100C5-L125C6
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external override receiveNonReentrant {
// assert and increment the nonce. no message shuffling
require(_nonce == ++inboundNonce[_srcChainId][_srcAddress], "LayerZero: wrong nonce");
LibraryConfig storage uaConfig = uaConfigLookup[_dstAddress];
// authentication to prevent cross-version message validation
// protects against a malicious library from passing arbitrary data
if (uaConfig.receiveVersion == DEFAULT_VERSION) {
require(defaultReceiveLibraryAddress == msg.sender, "LayerZero: invalid default library");
} else {
require(uaConfig.receiveLibraryAddress == msg.sender, "LayerZero: invalid library");
}
// block if any message blocking
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
require(sp.payloadHash == bytes32(0), "LayerZero: in message blocking");
try ILayerZeroReceiver(_dstAddress).lzReceive{gas: _gasLimit}(_srcChainId, _srcAddress, _nonce, _payload) {
// success, do nothing, end of the message delivery
} catch (bytes memory reason) {
// revert nonce if any uncaught errors/exceptions if the ua chooses the blocking mode
storedPayload[_srcChainId][_srcAddress] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));
emit PayloadStored(_srcChainId, _srcAddress, _dstAddress, _nonce, _payload, reason);
}
}
```
- As can be noticed, when another bridging call is made from the same source to the same destination chain again via the same channel (layerzero endpoint); it will not be executed as the channel is blocked since the `storedPayload[_srcChainId][_srcAddress]` is not empty (`require(sp.payloadHash == bytes32(0), "LayerZero: in message blocking")` is not satisfied).
- This occures as the `TempleGold.lzReceive()` doesn't implement a non-blocking mechanism where failed txns are stored to be retried manually later via [`retryPayload()`](https://github.com/LayerZero-Labs/LayerZero/blob/a1fb11a3b9c0ac449291816e71eacede4e36613e/contracts/Endpoint.sol#L127C14-L127C26) on the destination lz endpoint.
## Impact
- Blocking the bridging channel between `TempleGold` contracts resulting in:
1. disabling bridging functionality between the chains that got their channel blocked, until manually retried by the protocol.
2. user who got his bridged call blocked will lose his his `$TGLD` tokens until the failed called is retried manually by the protocol team.
## Tools Used
Manual Review.
## Recommendations
In `TempleGold.send()` function:
- Add a mechanism to enforce a sufficient gas is sent by the user to bridge his tokens (by checking that `msg.value` > [the recommended gas to be sent](https://github.com/LayerZero-Labs/LayerZero-v2/blob/7aebbd7c79b2dc818f7bb054aed2405ca076b9d6/packages/layerzero-v2/evm/oapp/contracts/oapp/OAppSender.sol#L47C2-L47C21) ).
- Add a mechanism to store failed received bridging txns in the `TempleGold` contract instead of reverting the txn (non-blocking receive mechanism), so that the bridging channel can't be blocked for whatever reason.
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Fee validation issue in send

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.