DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Incorrect calldata decoding in ParaSwapUtils affects token swaps and fund security

Title

Incorrect calldata decoding in ParaSwapUtils affects token swaps and fund security

Summary

The ParaSwapUtils.swap() function has a bug decoding calldata for Paraswap's simpleSwap() method.

Vulnerability Details

The ParaSwapUtils.swap() function tries to extract fromToken and fromAmount from calldata using incorrect memory offsets.
This mistake causes it to pull the wrong values, leading to issues with token approvals and transaction amounts.

Here’s what the SimpleData struct look like:

struct SimpleData {
address fromToken;
address toToken;
uint256 fromAmount;
uint256 toAmount;
uint256 expectedAmount;
address[] callees;
bytes exchangeData;
uint256[] startIndexes;
uint256[] values;
address payable beneficiary;
address payable partner;
uint256 feePercent;
bytes permit;
uint256 deadline;
bytes16 uuid;
}

The actual calldata layout for simpleSwap(SimpleData) is:

[0:4] - Function selector
[4:36] - SimpleData struct offset
[36:68] - fromToken (should be read here)
[68:100] - toToken
[100:132] - fromAmount

In the swap() function, the assembly code incorrectly reads fromToken and fromAmount:

assembly {
fromToken := mload(add(callData, 68)) // must be 36 instead
fromAmount := mload(add(callData, 100))
}

Impact

This bug causes the function to approve the wrong token or amount for transfers.

Tools Used

Manual Review

Recommendations

Update the assembly block to use the correct offsets for fromToken.

Updates

Lead Judging Commences

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

invalid_ParaswapUtils_incorrect_offset_SimpleSwap

Keepers use megaSwap with this struct: struct MegaSwapSellData { address fromToken; uint256 fromAmount; uint256 toAmount; uint256 expectedAmount; address payable beneficiary; Utils.MegaSwapPath[] path; address payable partner; uint256 feePercent; bytes permit; uint256 deadline; bytes16 uuid; } 32 first bytes of callData bytes array → length of the bytes array. 4 bytes selector, 32 bytes → offset of the struct → 68 bytes before the fromToken.

Support

FAQs

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