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 {
UsdTokenSwapConfig.Data storage tokenSwapData = UsdTokenSwapConfig.load();
UsdTokenSwapConfig.SwapRequest storage request = tokenSwapData.swapRequests[msg.sender][requestId];
if (request.processed) {
revert Errors.RequestAlreadyProcessed(msg.sender, requestId);
}
uint120 deadlineCache = request.deadline;
if (deadlineCache > block.timestamp) {
revert Errors.RequestNotExpired(msg.sender, requestId);
}
request.processed = true;
MarketMakingEngineConfiguration.Data storage marketMakingEngineConfiguration =
MarketMakingEngineConfiguration.load();
address usdToken = marketMakingEngineConfiguration.usdTokenOfEngine[engine];
uint256 baseFeeUsd = tokenSwapData.baseFeeUsd;
uint128 depositedUsdToken = request.amountIn;
marketMakingEngineConfiguration.distributeProtocolAssetReward(usdToken, baseFeeUsd);
uint256 refundAmountUsd = depositedUsdToken - baseFeeUsd;
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;
contractInstance.simulateDeposit(user, requestId, depositedUsdToken);
vm.prank(user);
contractInstance.refundSwap(requestId, engine);
uint256 expectedRefund = depositedUsdToken - baseFeeUsd - swapFeeUsd;
assertEq(contractInstance.getUserBalance(user), expectedRefund, "Incorrect refund amount!");
}
PoC
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;
contractInstance.simulateDeposit(user, requestId, depositedUsdToken);
vm.prank(user);
contractInstance.refundSwap(requestId, engine);
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);