Current implementation lacks the mechanism to clear borrowers debt either by full repayment of debt owned or closing of market .
This is problematic because if the same market approves a new depositor , internal calculations that rely of the debt amount will be affected since the market will still have pending debt.
function test_Poc() external {
// Create a lender address
address lender = vm.addr(0x123);
uint owed = market.totalDebts() - market.totalAssets();
assertEq(owed, 0 );
// Authorize the lender to interact with the market
_authorizeLender(lender);
// Lender deposits 100 units into the market
_deposit(lender, 100 ether);
// Verify the lender's balance in the market and the market's asset balance
assertEq(market.balanceOf(lender), 100 ether);
assertEq(asset.balanceOf(address(market)), 100 ether);
// Borrower borrows 70 units from the market
vm.startPrank(borrower);
market.borrow( 70 ether);
uint owedAfterBorrow = market.totalDebts() - market.totalAssets();
assertEq(owedAfterBorrow, 70 ether);
vm.stopPrank();
// Fast forward time to allow for withdrawal
fastForward(parameters.withdrawalBatchDuration + 1);
market.updateState();
// Lender requests a full withdrawal of their funds
vm.prank(lender);
market.queueFullWithdrawal();
uint256 expiry = block.timestamp + parameters.withdrawalBatchDuration;
// Fast forward time to make the market delinquent
fastForward(20 days);
market.updateState();
// Borrower prepares to repay delinquent debt
vm.startPrank(borrower);
asset.mint(borrower, 100 ether);
asset.approve(address(market), 100 ether);
// Verify the market is in a delinquent state
MarketState memory state0 = market.previousState();
assertEq(state0.isDelinquent, true);
// Borrower repays the delinquent debt
market.repayDelinquentDebt();
// Borrower prepares to execute the withdrawal
asset.mint(borrower, 100 ether);
asset.approve(address(market), 100 ether);
// Execute the withdrawal for the lender
market.executeWithdrawal(lender, uint32(expiry));
vm.stopPrank();
// Update and check the market state
market.updateState();
MarketState memory state = market.previousState();
assertEq(state.isDelinquent, false);
// Check the lender's final balance (should be 0 in the market)
uint256 finalBalance = asset.balanceOf(lender);
assertEq(market.balanceOf(lender), 0);
// Borrower repays the remaining debt
vm.startPrank(borrower);
asset.mint(borrower, 100 ether);
asset.approve(address(market), 100 ether);
market.repay(70 ether);
vm.stopPrank();
assertTrue(market.totalDebts() > 0 );
vm.startPrank(borrower);
asset.mint(borrower, 100 ether);
asset.approve(address(market), 100 ether);
market.closeMarket();
vm.stopPrank();
//@audit-issue : Debt is not cleared
assertTrue(market.totalDebts() > 0 );
}
This will affect future deposits on the same market, as the debt will continue to accrue.
Recommended Mitigation Steps
Add a final settlement step in the closeMarket() function to clear any remaining debts
Lines of code
https://github.com/code-423n4/2024-08-wildcat/blob/fe746cc0fbedc4447a981a50e6ba4c95f98b9fe1/src/market/WildcatMarket.sol#L226
Vulnerability details
Current implementation lacks the mechanism to clear borrowers debt either by full repayment of debt owned or closing of market .
This is problematic because if the same market approves a new depositor , internal calculations that rely of the debt amount will be affected since the market will still have pending debt.
Proof of Concept
https://github.com/code-423n4/2024-08-wildcat/blob/fe746cc0fbedc4447a981a50e6ba4c95f98b9fe1/src/market/WildcatMarket.sol#L226
This will affect future deposits on the same market, as the debt will continue to accrue.
Recommended Mitigation Steps
Add a final settlement step in the
closeMarket()
function to clear any remaining debtsAssessed type
Other