Permanent loss of tokens if swap data gets outdated
mediumLines of code
Vulnerability details
Impact
While sending funds through StargateBridgeAdapter, the user passes the swap data as a parameter. The flow is stargate sending tokens on the receiving chain into the StargateBridgeAdapter and executing sgReceive.
The issue here is that sgReceive will fail if the swap data gets outdated, but this is not going to make the whole transaction revert.
Stargate will still send the tokens to the StargateBridgeAdapter, and if the sgReceive fails, the swap will be cached for later execution.
See StargateComposer logic here: https://stargateprotocol.gitbook.io/stargate/stargate-composability/stargatecomposer.sol#sgreceive.
Now, tokens will be left sitting in the StargateBridgeAdapter contract, and since the user can only retry the transaction with the same swap data, the tokens will be stuck forever.
The impact is loss of transferred tokens for the user.
Proof of Concept
Consider the following flow:
- User invokes
StargateBridgeAdapter:bridge()function as part of the whole flow of callingUTB:bridgeAndExecute()function. - He is passing the swapData parameters to the remote chain.
StargateComposerfirst transfers the tokens to theStargateBridgeAdaptercontract.- After that the
StargateBridgeAdapter:sgReceive()function is executed. - It then calls
UTB:receiveFromBridgethat tries to execute the swap. - If the swap fails, which can frequently occur due to the fact that the swap data is outdated, most commonly minimum amount out gets outdated.
- The whole payload gets stored inside the
StargateComposercontract, and the tokens are left in theStargateBridgeAdaptercontract. - As the user can only retry the transaction with the same payload, the tokens will be stuck forever.
- An example of StargateComposer contract can be seen on: https://stargateprotocol.gitbook.io/stargate/developers/contract-addresses/mainnet#ethereum
Note: The application needs to use the StargateComposer contract as opposed to StargateRouter because it is transferring funds with payload, i.e. it executes sgReceive on the receiving chain.
You can only use StargateRouter directly if you're sending funds empty payload.
More on it: https://stargateprotocol.gitbook.io/stargate/stargate-composability
Tools Used
- Manual review
Recommended Mitigation Steps
Wrap the whole StargateBridgeAdapter:receiveFromBridge() call into a try/catch and if it reverts send the transferred tokens back to the user.
Assessed type
Other
