Part 2

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

[H-#] Unchecked Fee-on-Transfer Tokens in `CreditDelegationBranch` Cause Protocol Insolvency

Summary

The CreditDelegationBranch::depositCreditForMarket function assumes transferred token amounts match amount parameter. Fee-on-transfer tokens (e.g., STA, PAXG) will cause collateral under-accounting.

Vulnerability Details

Affected Code:

function depositCreditForMarket(...) {
IERC20(collateralAddr).safeTransferFrom(msg.sender, address(this), amount);
UD60x18 amountX18 = collateral.convertTokenAmountToUd60x18(amount); // Uses input amount
market.depositCredit(collateralAddr, amountX18); // Stores incorrect value
}

Exploit Scenario:

  1. Attacker deposits 100 STA (which charges 5% fee)

  2. Protocol receives 95 STA but records 100 STA

  3. Protocol becomes undercollateralized

Proof of Concept:

// Test with fee-on-transfer token
function testFeeOnTransferExploit() public {
address FEE_TOKEN = 0xSTA...;
uint256 DEPOSIT_AMOUNT = 100e18;
// Token charges 5% fee
deal(FEE_TOKEN, perpsEngine, DEPOSIT_AMOUNT);
vm.prank(perpsEngine);
creditDelegation.depositCreditForMarket(MARKET_ID, FEE_TOKEN, DEPOSIT_AMOUNT);
// Protocol balance = 95 STA but records 100 STA
assertEq(IERC20(FEE_TOKEN).balanceOf(address(creditDelegation)), 95e18);
assertEq(market.creditDeposits(FEE_TOKEN), 100e18); // Fails collateral backing
}

Impact

Direct Fund Loss: LPs over-redeem based on inflated balances

Protocol Insolvency: Total collateral < reported value

Tools Used

Manual analysis

Foundry test simulating fee-on-transfer

Recommendations

// Fix: Check balance changes
uint256 balanceBefore = IERC20(collateralAddr).balanceOf(address(this));
IERC20(collateralAddr).safeTransferFrom(msg.sender, address(this), amount);
uint256 received = IERC20(collateralAddr).balanceOf(address(this)) - balanceBefore;
UD60x18 amountX18 = collateral.convertTokenAmountToUd60x18(received);
Updates

Lead Judging Commences

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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