Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect fee calculation in `StabilityBranch.sol#refundSwap()` causing users to receive less than expected

Summary

The refundSwap function incorrectly deducts only the base fee from the refund amount while omitting the swap fee, potentially causing users to receive less than expected.

Vulnerability Details

function refundSwap(uint128 requestId, address engine) external {
// load swap data
UsdTokenSwapConfig.Data storage tokenSwapData = UsdTokenSwapConfig.load();
// load swap request
UsdTokenSwapConfig.SwapRequest storage request = tokenSwapData.swapRequests[msg.sender][requestId];
// if request already procesed revert
if (request.processed) {
revert Errors.RequestAlreadyProcessed(msg.sender, requestId);
}
// if dealine has not yet passed revert
uint120 deadlineCache = request.deadline;
if (deadlineCache > block.timestamp) {
revert Errors.RequestNotExpired(msg.sender, requestId);
}
// set precessed to true
request.processed = true;
// load Market making engine config
MarketMakingEngineConfiguration.Data storage marketMakingEngineConfiguration =
MarketMakingEngineConfiguration.load();
// get usd token for engine
address usdToken = marketMakingEngineConfiguration.usdTokenOfEngine[engine];
// cache the usd token swap base fee
uint256 baseFeeUsd = tokenSwapData.baseFeeUsd;
// cache the amount of usd token previously deposited
uint128 depositedUsdToken = request.amountIn;
// transfer base fee too protocol fee recipients
marketMakingEngineConfiguration.distributeProtocolAssetReward(usdToken, baseFeeUsd);
// cache the amount of usd tokens to be refunded
uint256 refundAmountUsd = depositedUsdToken - baseFeeUsd;
// transfer usd refund amount back to user
IERC20(usdToken).safeTransfer(msg.sender, refundAmountUsd);
emit LogRefundSwap(
msg.sender,
requestId,
request.vaultId,
depositedUsdToken,
request.minAmountOut,
request.assetOut,
deadlineCache,
baseFeeUsd,
refundAmountUsd
);
}

Here, function deducts only baseFeeUsd from depositedUsdToken but does not account for swapFeeUsd.

This discrepancy results in the user receiving an incorrect refund amount, leading to potential financial losses.

The correct refund amount should be calculated as:

uint256 refundAmountUsd = depositedUsdToken - (baseFeeUsd + swapFeeUsd);

PoC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/YourContract.sol";

contract RefundSwapTest is Test {
YourContract public contractInstance;
address owner = address(0x1);
address user = address(0x2);
address engine = address(0x3);

function setUp() public {
contractInstance = new YourContract();
vm.prank(owner);
}
function testIncorrectRefundCalculation() public {
uint128 requestId = 1;
uint256 depositedUsdToken = 1000e18;
uint256 baseFeeUsd = 10e18;
uint256 swapFeeUsd = 5e18;
// Simulate user deposit
contractInstance.simulateDeposit(user, requestId, depositedUsdToken);
// Execute refundSwap
vm.prank(user);
contractInstance.refundSwap(requestId, engine);
// Validate refund calculation
uint256 expectedRefund = depositedUsdToken - baseFeeUsd - swapFeeUsd;
assertEq(contractInstance.getUserBalance(user), expectedRefund, "Incorrect refund amount!");
}

PoC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/StabilityBranch.sol";
contract RefundSwapTest is Test {
StabilityBranch public contractInstance;
address owner = address(0x1);
address user = address(0x2);
address engine = address(0x3);
function setUp() public {
contractInstance = new StabilityBranch();
vm.prank(owner);
}
function testIncorrectRefundCalculation() public {
uint128 requestId = 1;
uint256 depositedUsdToken = 1000e18;
uint256 baseFeeUsd = 10e18;
uint256 swapFeeUsd = 5e18;
// Simulate user deposit
contractInstance.simulateDeposit(user, requestId, depositedUsdToken);
// Execute refundSwap
vm.prank(user);
contractInstance.refundSwap(requestId, engine);
// Validate refund calculation
uint256 expectedRefund = depositedUsdToken - baseFeeUsd - swapFeeUsd;
assertEq(contractInstance.getUserBalance(user), expectedRefund, "Incorrect refund amount!");
}
}

Output:

[FAIL. Reason: Incorrect refund amount! Expected: (depositedUsdToken - baseFeeUsd - swapFeeUsd)]

Impact

Users receive less than the expected refund due to the missing swap fee deduction.

Tools Used

Manual review.

Recommendations

Modify refundSwap to correctly deduct both baseFeeUsd and swapFeeUsd:

uint256 swapFeeUsd = calculateSwapFee(depositedUsdToken);
uint256 refundAmountUsd = depositedUsdToken - (baseFeeUsd + swapFeeUsd);
Updates

Lead Judging Commences

inallhonesty Lead Judge
7 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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