Open code423n4 opened 1 year ago
minhquanym marked the issue as low quality report
Consider QA
dmvt changed the severity to QA (Quality Assurance)
dmvt marked the issue as grade-b
@dmvt As stated in the report, cross chain messages are expensive so there is a non-trivial monetary impact to users here. I believe this has sufficient impact to be a medium severity issue
As stated in the report
No additional information provided. Ruling stands.
Lines of code
https://github.com/Tapioca-DAO/tap-token-audit/blob/59749be5bc2286f0bdbf59d7ddc258ddafd49a9f/contracts/tokens/BaseTapOFT.sol#L52-L65 https://github.com/Tapioca-DAO/tap-token-audit/blob/59749be5bc2286f0bdbf59d7ddc258ddafd49a9f/contracts/tokens/BaseTapOFT.sol#L309-L322 https://github.com/Tapioca-DAO/tapioca-sdk-audit/blob/90d1e8a16ebe278e86720bc9b69596f74320e749/src/contracts/lzApp/NonblockingLzApp.sol#L23-L41
Vulnerability details
Impact
For almost all cross chain messages sent via LayerZero in the Tapioca ecosystem, if a call fails on the destination chain the message is saved for retrying again on the destination chain. This has 2 purposes:
However the TapOFT messages do not follow this pattern. If the respective message fails the call doesn't revert and the failed message isn't saved. The end result is that the user has paid the significant LayerZero fee for a message that has failed, and now has to pay the same same large fee to retry again rather than just being able to retry the failed message on the destination chain. This is a poor user experience and costs the end user more of the source chain gas token than it should.
Proof of Concept
In
BaseTapOFT.sol
any messages received from another chain via LayerZero are executed throughnonBlockingLzReceive
:For the sake of argument, let's consider the
PT_UNLOCK_TWTAP
message that calls_unlockTwTapPosition
:As you can see from this part of the method, if exiting fails the error is caught and an event is emitted rather than reverting the call. As a result the message isn't saved for retrying. This can be seen from the
NonblockingLzApp.sol
contract:Here
_storeFailedMessage
is only called ifnonblockingLzReceive
reverts and therefore if_nonblockingLzReceive
reverts.Although
PT_LOCK_TWTAP
doesn't save the incoming message if the call fails, it does send the funds back to the user, so it isn't a complete waste. However I would suggest that it also reverts instead so that the message is saved and can be retried.Tools Used
Manual review
Recommended Mitigation Steps
Rather than emitting events stating that the message received via LayerZero has failed, TapOFT should instead revert execution to ensure that the message is available on the destination chain to retry again. This saves the user from having to pay the expensive LayerZero fee again and conforms to the same approach used by the rest of the codebase.
Assessed type
Other