Some token standards, such as ERC777, allow a callback to the source of the funds (the from address) before the balances are updated in transferFrom(). This callback could be used to re-enter the function and inflate the amount.
addtoPool() function and seizeLoan() function do the transfer of tokens before updating the state, which can lead to exploits if the token is a token that gives control to the sender, like ERC777 tokens.
addtoPool() increases the poolBalance of the pool before the transfering of loanToken from the lender of that pool. However, since there is no re-entrancy guard on this function, there is a risk of re-entrancy attack to increase the balance more without providing loanToken, which can be withdrawn later by the lender of the pool.
seizeLoan() transferring the collateralToken to the lender before updating the outstandingLoans of that pool and delete the loan. However, since there is no re-entrancy guard on this function, there is a risk of re-entrancy attack to keep receiving the collateral assets from the contract.
setPool() transferring the loanToken difference back to the lender if the param p.poolBalance < currentBalance of the pool before updating the new pool configs to the pool. However, since there is no re-entrancy guard on this function, there is a risk of re-entrancy attack to keep receiving the loan assets from the contract.
##POC
for addToPool():
Initial state: poolBalance = 0
Adding to pool 1000 loanToken amount should increase the poolBalance to 1000, but the lender can use re-entrancy to re-enter the addToPool with the same 1000 amount.
Outer addToPool(1000): poolBalance = 1000. Control is given to attacker ...
Inner addToPool(1000): poolBalance = 2000.
Withdrawing the 2000 loanToken via removeFromPool(2000), The attacker makes a profit of 2000 - 1000 = 1000 loantoken.
Repeating the attack until the loanToken assets of contract is drained.
seizeLoan() case would be the same, lender call seizeLoan(loanId) and then re-enter it until there are none of collateral assets left of that loan in the contract.
setPool() case would be the same, lender call setPool(p) with p.poolBalance < currentBalance of the pool and then re-enter it until there are none of the loanToken in the pool's config left of in the contract.
Fund losing for other lenders and borrowers.
Manual
Consider adding nonReentrant modifier from OZ's ReentrancyGuard.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.