Submitted by 0x73696d616f, also found by KIntern_NA and bin2chen
https://github.com/Tapioca-DAO/tapiocaz-audit/blob/bcf61f79464cfdc0484aa272f9f6e28d5de36a8f/contracts/tOFT/BaseTOFT.sol#L539-L545
https://github.com/Tapioca-DAO/tapiocaz-audit/blob/bcf61f79464cfdc0484aa272f9f6e28d5de36a8f/contracts/tOFT/modules/BaseTOFTOptionsModule.sol#L153-L159
Exercise option cross chain message in the (m)TapiocaOFT will always revert in the destination, but works in the source chain, where it debits the funds from users. Thus, these funds will not be credited in the destination and are forever lost.
In the BaseTOFT, if the packet from the received cross chain message in lzReceive() is of type PT_TAP_EXERCISE, it delegate calls to the BaseTOFTOptionsModule:
In the BaseTOFTOptionsModule, the exercise() function is declared as:
Notice that the address module argument is specified in the exercise() function declaration, but not in the _nonBlockingLzReceive() call to it. This will make the message always revert because it fails when decoding the arguments to the function call, due to the extra address module argument.
The following POC illustrates this behaviour. The exerciseOption() cross chain message fails on the destination:
Vscode, Foundry
Adding the extra module parameter when encoding the function call in _nonBlockingLzReceive() would be vulnerable to someone calling the BaseTOFTOptionsModule directly on function exercise() with a malicious module argument. Its safer to remove the module argument and call exerciseInternal() directly, which should work since its a public function.
0xRektora (Tapioca) confirmed
