Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repay/Withdraw max #123

Closed
wants to merge 12 commits into from
Closed
27 changes: 21 additions & 6 deletions src/Blue.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,22 @@ contract Blue {
function withdraw(Market calldata market, uint256 amount, address onBehalf) external {
makcandrov marked this conversation as resolved.
Show resolved Hide resolved
Id id = market.id();
require(lastUpdate[id] != 0, "unknown market");
require(amount != 0, "zero amount");
require(isSenderOrIsApproved(onBehalf), "not approved");

accrueInterests(market, id);

uint256 shares = amount.toSharesUp(totalSupply[id], totalSupplyShares[id]);
uint256 shares;
if (amount == type(uint256).max) {
amount = supplyShare[id][onBehalf].toAssetsDown(totalSupply[id], totalSupplyShares[id]);
shares = supplyShare[id][onBehalf];
} else {
shares = amount.toSharesUp(totalSupply[id], totalSupplyShares[id]);
}

require(amount != 0, "zero amount");
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved

supplyShare[id][onBehalf] -= shares;
totalSupplyShares[id] -= shares;

totalSupply[id] -= amount;

require(totalBorrow[id] <= totalSupply[id], "not enough liquidity");
Expand Down Expand Up @@ -162,14 +169,21 @@ contract Blue {
function repay(Market calldata market, uint256 amount, address onBehalf) external {
Id id = market.id();
require(lastUpdate[id] != 0, "unknown market");
require(amount != 0, "zero amount");

accrueInterests(market, id);

uint256 shares = amount.toSharesDown(totalBorrow[id], totalBorrowShares[id]);
uint256 shares;
if (amount == type(uint256).max) {
amount = borrowShare[id][onBehalf].toAssetsUp(totalBorrow[id], totalBorrowShares[id]);
shares = borrowShare[id][onBehalf];
} else {
shares = amount.toSharesDown(totalBorrow[id], totalBorrowShares[id]);
}

require(amount != 0, "zero amount");

borrowShare[id][onBehalf] -= shares;
totalBorrowShares[id] -= shares;

totalBorrow[id] -= amount;

market.borrowableAsset.safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -193,6 +207,7 @@ contract Blue {
function withdrawCollateral(Market calldata market, uint256 amount, address onBehalf) external {
Id id = market.id();
require(lastUpdate[id] != 0, "unknown market");
if (amount == type(uint256).max) amount = collateral[id][msg.sender];
Rubilmax marked this conversation as resolved.
Show resolved Hide resolved
require(amount != 0, "zero amount");
require(isSenderOrIsApproved(onBehalf), "not approved");

Expand Down
43 changes: 43 additions & 0 deletions test/forge/Blue.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,20 @@ contract BlueTest is Test {
);
}

function testWithdrawAll(uint256 amountLent, uint256 amountBorrowed) public {
amountLent = bound(amountLent, 1, 2 ** 64);
amountBorrowed = bound(amountBorrowed, 1, 2 ** 64);
vm.assume(amountLent >= amountBorrowed);

borrowableAsset.setBalance(address(this), amountLent);
blue.supply(market, amountLent, address(this));
blue.withdraw(market, type(uint256).max, address(this));

assertEq(blue.supplyShare(id, address(this)), 0, "supply share");
assertEq(borrowableAsset.balanceOf(address(this)), amountLent, "this balance");
assertEq(borrowableAsset.balanceOf(address(blue)), 0, "blue balance");
}

function testCollateralRequirements(
uint256 amountCollateral,
uint256 amountBorrowed,
Expand Down Expand Up @@ -447,6 +461,23 @@ contract BlueTest is Test {
assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed + amountRepaid, "blue balance");
}

function testRepayAll(uint256 amountLent, uint256 amountBorrowed) public {
amountLent = bound(amountLent, 1, 2 ** 64);
amountBorrowed = bound(amountBorrowed, 1, amountLent);

borrowableAsset.setBalance(address(this), amountLent);
blue.supply(market, amountLent, address(this));

vm.startPrank(BORROWER);
blue.borrow(market, amountBorrowed, BORROWER);
blue.repay(market, type(uint256).max, BORROWER);
vm.stopPrank();

assertEq(blue.borrowShare(id, BORROWER), 0, "borrow share");
assertEq(borrowableAsset.balanceOf(BORROWER), 0, "BORROWER balance");
assertEq(borrowableAsset.balanceOf(address(blue)), amountLent, "blue balance");
}

function testSupplyCollateralOnBehalf(uint256 amount, address onBehalf) public {
vm.assume(onBehalf != address(blue));
amount = bound(amount, 1, 2 ** 64);
Expand Down Expand Up @@ -479,6 +510,18 @@ contract BlueTest is Test {
assertEq(collateralAsset.balanceOf(address(blue)), amountDeposited - amountWithdrawn, "blue balance");
}

function testWithdrawCollateralAll(uint256 amountDeposited) public {
amountDeposited = bound(amountDeposited, 1, 2 ** 64);

collateralAsset.setBalance(address(this), amountDeposited);
blue.supplyCollateral(market, amountDeposited, address(this));
blue.withdrawCollateral(market, type(uint256).max, address(this));

assertEq(blue.collateral(id, address(this)), 0, "this collateral");
assertEq(collateralAsset.balanceOf(address(this)), amountDeposited, "this balance");
assertEq(collateralAsset.balanceOf(address(blue)), 0, "blue balance");
}

function testLiquidate(uint256 amountLent) public {
borrowableOracle.setPrice(1e18);
amountLent = bound(amountLent, 1000, 2 ** 64);
Expand Down