20,000 USDC
View results
Submission Details
Severity: high
Valid

Contracts do not work with fee-on-transfer tokens

Summary

Some tokens take a transfer fee (e.g. STA, PAXG), some do not currently charge a fee but may do so in the future (e.g. USDT, USDC).
Without measuring the balance before and after the transfer, there's no way to ensure that enough tokens were transferred, in the cases where the token has a fee-on-transfer mechanic. If there are latent funds in the contract, subsequent transfers will succeed.

Proof Of Concept

File: Lender.sol
203: IERC20(pools[poolId].loanToken).transfer(msg.sender, amount);

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L203

File: Lender.sol
267: IERC20(loan.loanToken).transfer(feeReceiver, fees);
269: IERC20(loan.loanToken).transfer(msg.sender, debt - fees);

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L267

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L269

File: Lender.sol
403: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);
505: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);
656: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L403

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L505

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L656

File: Lender.sol
403: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);
505: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);
656: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L403

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L505

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L656

File: Lender.sol
563: IERC20(loan.collateralToken).transfer(feeReceiver, govFee);

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L563

File: Lender.sol
651: IERC20(loan.loanToken).transfer(feeReceiver, fee);
653: IERC20(loan.loanToken).transfer(msg.sender, debt - debtToPay - fee);
403: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);
505: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);
656: IERC20(loan.loanToken).transfer(feeReceiver, protocolInterest);

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L651

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L653

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L403

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L505

https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L656

Recommended Mitigation Steps

  • Consider comparing before and after balance to get the actual transferred amount.

  • Alternatively, disallow tokens with fee-on-transfer mechanics to be added as reward tokens.

Support

FAQs

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