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.

Give us feedback!