Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/BorrowController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ contract BorrowController {
uint lastUpdated = DBR.lastUpdated(borrower);
uint debts = DBR.debts(borrower);
//Check to prevent effects of edge case bug
if(lastUpdated > 0 && debts == 0 && lastUpdated != block.timestamp){
uint timeElapsed = block.timestamp - lastUpdated;
if(lastUpdated > 0 && debts * timeElapsed < 365 days && lastUpdated != block.timestamp){
//Important check, otherwise a user could repeatedly mint themsevles DBR
require(DBR.markets(msg.sender), "Message sender is not a market");
uint deficit = (block.timestamp - lastUpdated) * amount / 365 days;
Expand All @@ -120,7 +121,7 @@ contract BorrowController {
//If the chainlink oracle price feed is stale, deny borrow
if(isPriceStale(msg.sender)) return false;
//If the message sender is not a contract, then there's no need check allowlist
if(msgSender == tx.origin) return true;
if(msgSender == tx.origin && msgSender.code.length == 0) return true;
return contractAllowlist[msgSender];
}

Expand Down
116 changes: 116 additions & 0 deletions test/BorrowController.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,122 @@ contract BorrowControllerTest is FiRMBaseTest {
);
}

function test_BorrowAllowed_True_Where_EdgeCaseBugDebtNonZero()
public
{
uint testAmount = 1e18;
gibWeth(user, testAmount);
uint halfBorrow = getMaxBorrowAmount(testAmount) / 2;
gibDOLA(address(market), halfBorrow * 2);
vm.startPrank(user, user);
deposit(testAmount);
market.borrow(halfBorrow);
market.repay(user, halfBorrow-1);
vm.stopPrank();

assertEq(market.debts(user), 1, "User debt not 1");
assertEq(dbr.balanceOf(user), 0, "DBR balance of user is not 0 before time skip");
vm.warp(block.timestamp + 30 days);
ethFeed.changeUpdatedAt(block.timestamp);
vm.prank(gov);
dbr.addMinter(address(borrowController));
vm.prank(address(market), user);
assertTrue(
borrowController.borrowAllowed(user, user, 1)
);
vm.startPrank(user, user);
assertGt(market.getCreditLimit(user), 0, "User has no credit limit");
market.borrow(market.getCreditLimit(user) / 100);
assertLe(dbr.deficitOf(user), 30 days * 1, "Deficit of user more than expected");
assertEq(dbr.balanceOf(user), 0, "DBR balance of user is not 0");
}

function test_BorrowAllowed_True_Where_EdgeCaseBugDebtNonZero365Days()
public
{
uint testAmount = 1e18;
gibWeth(user, testAmount);
uint halfBorrow = getMaxBorrowAmount(testAmount) / 2;
gibDOLA(address(market), halfBorrow * 2);
vm.startPrank(user, user);
deposit(testAmount);
market.borrow(halfBorrow);
market.repay(user, halfBorrow-1);
vm.stopPrank();

assertEq(market.debts(user), 1, "User debt not 1");
assertEq(dbr.balanceOf(user), 0, "DBR balance of user is not 0 before time skip");
vm.warp(block.timestamp + 365 days);
ethFeed.changeUpdatedAt(block.timestamp);
vm.prank(gov);
dbr.addMinter(address(borrowController));
vm.prank(address(market), user);
assertTrue(
borrowController.borrowAllowed(user, user, 1)
);
vm.startPrank(user, user);
assertGt(market.getCreditLimit(user), 0, "User has no credit limit");
uint creditLimit = market.getCreditLimit(user);
vm.expectRevert("DBR Deficit");
market.borrow(creditLimit / 100);
dbr.accrueDueTokens(user);
assertEq(dbr.deficitOf(user), 1);
}


function test_BorrowAllowed_True_Where_EdgeCaseBugDebtNonZeroFuzz(uint timeElapsed)
public
{
uint timeElapsed = timeElapsed % 365 days;
uint testAmount = 1e18;
gibWeth(user, testAmount);
uint halfBorrow = getMaxBorrowAmount(testAmount) / 2;
gibDOLA(address(market), halfBorrow * 2);
vm.startPrank(user, user);
deposit(testAmount);
market.borrow(halfBorrow);
market.repay(user, halfBorrow-1);
vm.stopPrank();

assertEq(market.debts(user), 1, "User debt not 1");
assertEq(dbr.balanceOf(user), 0, "DBR balance of user is not 0 before time skip");
vm.warp(block.timestamp + timeElapsed);
ethFeed.changeUpdatedAt(block.timestamp);
vm.prank(gov);
dbr.addMinter(address(borrowController));
vm.prank(address(market), user);
assertTrue(
borrowController.borrowAllowed(user, user, 1)
);
vm.startPrank(user, user);
assertGt(market.getCreditLimit(user), 0, "User has no credit limit");
market.borrow(market.getCreditLimit(user) / 100);
assertLe(dbr.deficitOf(user), timeElapsed * 1, "Deficit of user more than expected");
assertEq(dbr.balanceOf(user), 0, "DBR balance of user is not 0");
}

function test_BorrowAllowed_False_Where_EdgeCaseBugTriggeredWithMinimalDebt()
public
{
uint testAmount = 1e18;
gibWeth(user, testAmount);
uint maxBorrow = getMaxBorrowAmount(testAmount);
gibDOLA(address(market), maxBorrow);
vm.startPrank(user, user);
deposit(testAmount);
market.borrow(maxBorrow);
market.repay(user, maxBorrow-1);
vm.stopPrank();

vm.warp(block.timestamp + 1);
vm.prank(address(market), user);
assertFalse(
borrowController.borrowAllowed(user, user, 1),
"User was allowed to borrow"
);
}


function test_BorrowAllowed_True_Where_EdgeCaseBugTriggeredAndAMinter()
public
{
Expand Down
Loading