In LendgineRouter.sol, mintCallback() will transfer token1 (collateral) to Lendgine.sol contract upon minting of Power Tokens. If token1 is a fee-on-transfer token, these transfers will incur fees and the recipient (Lendgine.sol) will receive a deducted amount that is less than the collateral amount, causing the mint to always fail.
As Numoen is permissionless, anyone can create a pool with fee-on-transfer ERC20 tokens. Example of these fee-on-transfer tokens are STA and PAXG. And some tokens (e.g. USDT) has fee-on-transfer support disabled currently but may enable it in the future.
Proof of Concept
Start by calling LengineRouter.mint() to trigger the mintCallback() function.
mintCallback() will initiate token1 transfers to Lendgine contract (which is the msg.sender) via swap(), SafeTransferLib.safeTransfer() and pay(). Lendgine contract will receive a reduced amount due to fee deduction on transfer.
Lines of code
https://github.com/code-423n4/2023-01-numoen/blob/main/src/periphery/LendgineRouter.sol#L142-L169 https://github.com/code-423n4/2023-01-numoen/blob/main/src/periphery/LendgineRouter.sol#L87-L124 https://github.com/code-423n4/2023-01-numoen/blob/main/src/core/Lendgine.sol#L95-L99
Vulnerability details
Impact
In LendgineRouter.sol, mintCallback() will transfer token1 (collateral) to Lendgine.sol contract upon minting of Power Tokens. If token1 is a fee-on-transfer token, these transfers will incur fees and the recipient (Lendgine.sol) will receive a deducted amount that is less than the collateral amount, causing the mint to always fail.
As Numoen is permissionless, anyone can create a pool with fee-on-transfer ERC20 tokens. Example of these fee-on-transfer tokens are STA and PAXG. And some tokens (e.g. USDT) has fee-on-transfer support disabled currently but may enable it in the future.
Proof of Concept
Start by calling LengineRouter.mint() to trigger the mintCallback() function.
https://github.com/code-423n4/2023-01-numoen/blob/main/src/periphery/LendgineRouter.sol#L142-L169
mintCallback() will initiate token1 transfers to Lendgine contract (which is the msg.sender) via swap(), SafeTransferLib.safeTransfer() and pay(). Lendgine contract will receive a reduced amount due to fee deduction on transfer.
https://github.com/code-423n4/2023-01-numoen/blob/main/src/periphery/LendgineRouter.sol#L87-L124
As Lendgine contract is expecting the full amount of collateral to be received based on the balance increase, the mint transaction will revert.
https://github.com/code-423n4/2023-01-numoen/blob/main/src/core/Lendgine.sol#L95-L99
Recommended Mitigation Steps
One potential mitigation is to take into account the transfer fee during the transfer request. Another option is to block these customised tokens.