From 7ae5fe3f162b1d5316eb0e632ce87f795ea5e2ce Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Thu, 27 Jul 2023 09:58:25 +0200 Subject: [PATCH 1/9] feat: add receiver param --- src/Blue.sol | 12 ++++----- test/forge/Blue.t.sol | 60 +++++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/Blue.sol b/src/Blue.sol index 68596909a..1c8acc87e 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -120,7 +120,7 @@ contract Blue { market.borrowableAsset.safeTransferFrom(msg.sender, address(this), amount); } - function withdraw(Market memory market, uint256 amount, address onBehalf) external { + function withdraw(Market memory market, uint256 amount, address onBehalf, address receiver) external { Id id = market.id(); require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED); require(amount != 0, Errors.ZERO_AMOUNT); @@ -136,12 +136,12 @@ contract Blue { require(totalBorrow[id] <= totalSupply[id], Errors.INSUFFICIENT_LIQUIDITY); - market.borrowableAsset.safeTransfer(msg.sender, amount); + market.borrowableAsset.safeTransfer(receiver, amount); } // Borrow management. - function borrow(Market memory market, uint256 amount, address onBehalf) external { + function borrow(Market memory market, uint256 amount, address onBehalf, address receiver) external { Id id = market.id(); require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED); require(amount != 0, Errors.ZERO_AMOUNT); @@ -158,7 +158,7 @@ contract Blue { require(_isHealthy(market, id, onBehalf), Errors.INSUFFICIENT_COLLATERAL); require(totalBorrow[id] <= totalSupply[id], Errors.INSUFFICIENT_LIQUIDITY); - market.borrowableAsset.safeTransfer(msg.sender, amount); + market.borrowableAsset.safeTransfer(receiver, amount); } function repay(Market memory market, uint256 amount, address onBehalf) external { @@ -192,7 +192,7 @@ contract Blue { market.collateralAsset.safeTransferFrom(msg.sender, address(this), amount); } - function withdrawCollateral(Market memory market, uint256 amount, address onBehalf) external { + function withdrawCollateral(Market memory market, uint256 amount, address onBehalf, address receiver) external { Id id = market.id(); require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED); require(amount != 0, Errors.ZERO_AMOUNT); @@ -204,7 +204,7 @@ contract Blue { require(_isHealthy(market, id, onBehalf), Errors.INSUFFICIENT_COLLATERAL); - market.collateralAsset.safeTransfer(msg.sender, amount); + market.collateralAsset.safeTransfer(receiver, amount); } // Liquidation. diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index cc88d8835..7800f6e24 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -254,7 +254,7 @@ contract BlueTest is Test { blue.supply(market, amountLent, address(this)); vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); uint256 totalSupplyBefore = blue.totalSupply(id); uint256 totalSupplySharesBefore = blue.totalSupplyShares(id); @@ -264,7 +264,7 @@ contract BlueTest is Test { collateralAsset.setBalance(address(this), 1); blue.supplyCollateral(market, 1, address(this)); - blue.withdrawCollateral(market, 1, address(this)); + blue.withdrawCollateral(market, 1, address(this), address(this)); uint256 totalSupplyAfter = blue.totalSupply(id); vm.assume(totalSupplyAfter > totalSupplyBefore); @@ -305,19 +305,19 @@ contract BlueTest is Test { blue.supply(market, amountLent, address(this)); if (amountBorrowed == 0) { - blue.borrow(market, amountBorrowed, address(this)); + blue.borrow(market, amountBorrowed, address(this), address(this)); return; } if (amountBorrowed > amountLent) { vm.prank(BORROWER); vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); return; } vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); assertEq(blue.borrowShare(id, BORROWER), amountBorrowed * SharesMath.VIRTUAL_SHARES, "borrow share"); assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "BORROWER balance"); @@ -334,7 +334,7 @@ contract BlueTest is Test { blue.supply(market, amountLent, address(this)); vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); if (amountWithdrawn > amountLent - amountBorrowed) { if (amountWithdrawn > amountLent) { @@ -342,11 +342,11 @@ contract BlueTest is Test { } else { vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); } - blue.withdraw(market, amountWithdrawn, address(this)); + blue.withdraw(market, amountWithdrawn, address(this), address(this)); return; } - blue.withdraw(market, amountWithdrawn, address(this)); + blue.withdraw(market, amountWithdrawn, address(this), address(this)); assertApproxEqAbs( blue.supplyShare(id, address(this)), @@ -386,11 +386,11 @@ contract BlueTest is Test { uint256 borrowValue = amountBorrowed.mulWadUp(priceBorrowable); if (borrowValue == 0 || (collateralValue > 0 && borrowValue <= collateralValue.mulWadDown(LLTV))) { vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); } else { vm.prank(BORROWER); vm.expectRevert(bytes(Errors.INSUFFICIENT_COLLATERAL)); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); } } @@ -403,7 +403,7 @@ contract BlueTest is Test { blue.supply(market, amountLent, address(this)); vm.startPrank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); blue.repay(market, amountRepaid, BORROWER); vm.stopPrank(); @@ -430,7 +430,7 @@ contract BlueTest is Test { blue.supply(market, amountLent, address(this)); vm.prank(onBehalf); - blue.borrow(market, amountBorrowed, onBehalf); + blue.borrow(market, amountBorrowed, onBehalf, onBehalf); blue.repay(market, amountRepaid, onBehalf); @@ -465,11 +465,11 @@ contract BlueTest is Test { if (amountWithdrawn > amountDeposited) { vm.expectRevert(stdError.arithmeticError); - blue.withdrawCollateral(market, amountWithdrawn, address(this)); + blue.withdrawCollateral(market, amountWithdrawn, address(this), address(this)); return; } - blue.withdrawCollateral(market, amountWithdrawn, address(this)); + blue.withdrawCollateral(market, amountWithdrawn, address(this), address(this)); assertEq(blue.collateral(id, address(this)), amountDeposited - amountWithdrawn, "this collateral"); assertEq(collateralAsset.balanceOf(address(this)), amountWithdrawn, "this balance"); @@ -496,7 +496,7 @@ contract BlueTest is Test { // Borrow vm.startPrank(BORROWER); blue.supplyCollateral(market, amountCollateral, BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); vm.stopPrank(); // Price change @@ -539,7 +539,7 @@ contract BlueTest is Test { // Borrow vm.startPrank(BORROWER); blue.supplyCollateral(market, amountCollateral, BORROWER); - blue.borrow(market, amountBorrowed, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, BORROWER); vm.stopPrank(); // Price change @@ -594,10 +594,10 @@ contract BlueTest is Test { blue.supply(marketFuzz, 1, address(this)); vm.expectRevert("unknown market"); - blue.withdraw(marketFuzz, 1, address(this)); + blue.withdraw(marketFuzz, 1, address(this), address(this)); vm.expectRevert("unknown market"); - blue.borrow(marketFuzz, 1, address(this)); + blue.borrow(marketFuzz, 1, address(this), address(this)); vm.expectRevert("unknown market"); blue.repay(marketFuzz, 1, address(this)); @@ -606,7 +606,7 @@ contract BlueTest is Test { blue.supplyCollateral(marketFuzz, 1, address(this)); vm.expectRevert("unknown market"); - blue.withdrawCollateral(marketFuzz, 1, address(this)); + blue.withdrawCollateral(marketFuzz, 1, address(this), address(this)); vm.expectRevert("unknown market"); blue.liquidate(marketFuzz, address(0), 1); @@ -617,10 +617,10 @@ contract BlueTest is Test { blue.supply(market, 0, address(this)); vm.expectRevert("zero amount"); - blue.withdraw(market, 0, address(this)); + blue.withdraw(market, 0, address(this), address(this)); vm.expectRevert("zero amount"); - blue.borrow(market, 0, address(this)); + blue.borrow(market, 0, address(this), address(this)); vm.expectRevert("zero amount"); blue.repay(market, 0, address(this)); @@ -629,7 +629,7 @@ contract BlueTest is Test { blue.supplyCollateral(market, 0, address(this)); vm.expectRevert("zero amount"); - blue.withdrawCollateral(market, 0, address(this)); + blue.withdrawCollateral(market, 0, address(this), address(this)); vm.expectRevert("zero amount"); blue.liquidate(market, address(0), 0); @@ -639,13 +639,13 @@ contract BlueTest is Test { amount = bound(amount, 1, type(uint256).max / SharesMath.VIRTUAL_SHARES); vm.expectRevert(stdError.arithmeticError); - blue.withdraw(market, amount, address(this)); + blue.withdraw(market, amount, address(this), address(this)); vm.expectRevert(stdError.arithmeticError); blue.repay(market, amount, address(this)); vm.expectRevert(stdError.arithmeticError); - blue.withdrawCollateral(market, amount, address(this)); + blue.withdrawCollateral(market, amount, address(this), address(this)); } function testSetApproval(address manager, bool isAllowed) public { @@ -659,11 +659,11 @@ contract BlueTest is Test { vm.startPrank(attacker); vm.expectRevert("not approved"); - blue.withdraw(market, 1, address(this)); + blue.withdraw(market, 1, address(this), address(this)); vm.expectRevert("not approved"); - blue.withdrawCollateral(market, 1, address(this)); + blue.withdrawCollateral(market, 1, address(this), address(this)); vm.expectRevert("not approved"); - blue.borrow(market, 1, address(this)); + blue.borrow(market, 1, address(this), address(this)); vm.stopPrank(); } @@ -679,9 +679,9 @@ contract BlueTest is Test { vm.startPrank(manager); - blue.withdraw(market, 1 ether, address(this)); - blue.withdrawCollateral(market, 1 ether, address(this)); - blue.borrow(market, 1 ether, address(this)); + blue.withdraw(market, 1 ether, address(this), address(this)); + blue.withdrawCollateral(market, 1 ether, address(this), address(this)); + blue.borrow(market, 1 ether, address(this), address(this)); vm.stopPrank(); } From e3024e85b906d9a0f714f6ed1088984236b33f73 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Thu, 27 Jul 2023 11:44:56 +0200 Subject: [PATCH 2/9] test: fix hardat tests --- test/hardhat/Blue.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/hardhat/Blue.spec.ts b/test/hardhat/Blue.spec.ts index 08193f88e..3b7d3fe0f 100644 --- a/test/hardhat/Blue.spec.ts +++ b/test/hardhat/Blue.spec.ts @@ -124,7 +124,7 @@ describe("Blue", () => { if (random() < 2 / 3) { await blue.connect(user).supply(market, amount, user.address); - await blue.connect(user).withdraw(market, amount.div(2), user.address); + await blue.connect(user).withdraw(market, amount.div(2), user.address, user.address); } else { const totalSupply = await blue.totalSupply(id); const totalBorrow = await blue.totalBorrow(id); @@ -134,9 +134,9 @@ describe("Blue", () => { if (amount > BigNumber.from(0)) { await blue.connect(user).supplyCollateral(market, amount, user.address); - await blue.connect(user).borrow(market, amount.div(2), user.address); + await blue.connect(user).borrow(market, amount.div(2), user.address, user.address); await blue.connect(user).repay(market, amount.div(4), user.address); - await blue.connect(user).withdrawCollateral(market, amount.div(8), user.address); + await blue.connect(user).withdrawCollateral(market, amount.div(8), user.address, user.address); } } } @@ -164,11 +164,11 @@ describe("Blue", () => { // We use 2 different users to borrow from a market so that liquidations do not put the borrow storage back to 0 on that market. await blue.connect(user).supply(market, amount, user.address); await blue.connect(user).supplyCollateral(market, amount, user.address); - await blue.connect(user).borrow(market, borrowedAmount, user.address); + await blue.connect(user).borrow(market, borrowedAmount, user.address, user.address); await blue.connect(borrower).supply(market, amount, borrower.address); await blue.connect(borrower).supplyCollateral(market, amount, borrower.address); - await blue.connect(borrower).borrow(market, borrowedAmount, borrower.address); + await blue.connect(borrower).borrow(market, borrowedAmount, borrower.address, user.address); await borrowableOracle.setPrice(BigNumber.WAD.mul(1000)); From 83afaa4f39f879ce972bfe5a06937bb0e41e2dd6 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Fri, 28 Jul 2023 09:15:27 +0200 Subject: [PATCH 3/9] test: add tests --- test/forge/Blue.t.sol | 51 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index 7800f6e24..b7fc4300f 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -304,11 +304,6 @@ contract BlueTest is Test { borrowableAsset.setBalance(address(this), amountLent); blue.supply(market, amountLent, address(this)); - if (amountBorrowed == 0) { - blue.borrow(market, amountBorrowed, address(this), address(this)); - return; - } - if (amountBorrowed > amountLent) { vm.prank(BORROWER); vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); @@ -324,6 +319,21 @@ contract BlueTest is Test { assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed, "blue balance"); } + function testBorrowReceiver(uint256 amountLent, uint256 amountBorrowed, address receiver) public { + amountLent = bound(amountLent, 1, 2 ** 64); + amountBorrowed = bound(amountBorrowed, 1, amountLent); + + borrowableAsset.setBalance(address(this), amountLent); + blue.supply(market, amountLent, address(this)); + + vm.prank(BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, receiver); + + assertEq(blue.borrowShare(id, BORROWER), amountBorrowed * SharesMath.VIRTUAL_SHARES, "borrow share"); + assertEq(borrowableAsset.balanceOf(receiver), amountBorrowed, "receiver balance"); + assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed, "blue balance"); + } + function testWithdraw(uint256 amountLent, uint256 amountWithdrawn, uint256 amountBorrowed) public { amountLent = bound(amountLent, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, 2 ** 64); @@ -360,6 +370,24 @@ contract BlueTest is Test { ); } + function testWithdrawReceiver(uint256 amountLent, uint256 amountWithdrawn, address receiver) public { + amountLent = bound(amountLent, 1, 2 ** 64); + amountWithdrawn = bound(amountWithdrawn, 1, amountLent); + + borrowableAsset.setBalance(address(this), amountLent); + blue.supply(market, amountLent, address(this)); + blue.withdraw(market, amountWithdrawn, address(this), receiver); + + assertApproxEqAbs( + blue.supplyShare(id, address(this)), + (amountLent - amountWithdrawn) * SharesMath.VIRTUAL_SHARES, + 100, + "supply share" + ); + assertEq(borrowableAsset.balanceOf(receiver), amountWithdrawn, "receiver balance"); + assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountWithdrawn, "blue balance"); + } + function testCollateralRequirements( uint256 amountCollateral, uint256 amountBorrowed, @@ -476,6 +504,19 @@ contract BlueTest is Test { assertEq(collateralAsset.balanceOf(address(blue)), amountDeposited - amountWithdrawn, "blue balance"); } + function testWithdrawCollateral(uint256 amountDeposited, uint256 amountWithdrawn, address receiver) public { + amountDeposited = bound(amountDeposited, 1, 2 ** 64); + amountWithdrawn = bound(amountWithdrawn, 1, amountDeposited); + + collateralAsset.setBalance(address(this), amountDeposited); + blue.supplyCollateral(market, amountDeposited, address(this)); + blue.withdrawCollateral(market, amountWithdrawn, address(this), receiver); + + assertEq(blue.collateral(id, address(this)), amountDeposited - amountWithdrawn, "this collateral"); + assertEq(collateralAsset.balanceOf(receiver), amountWithdrawn, "receiver balance"); + assertEq(collateralAsset.balanceOf(address(blue)), amountDeposited - amountWithdrawn, "blue balance"); + } + function testLiquidate(uint256 amountLent) public { borrowableOracle.setPrice(1e18); amountLent = bound(amountLent, 1000, 2 ** 64); From 729c8989d481d111c4457fa583a9445594dd4523 Mon Sep 17 00:00:00 2001 From: MathisGD Date: Fri, 28 Jul 2023 12:25:49 +0200 Subject: [PATCH 4/9] test: fix receiver test --- test/forge/Blue.t.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index b7fc4300f..5b500945a 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -320,6 +320,7 @@ contract BlueTest is Test { } function testBorrowReceiver(uint256 amountLent, uint256 amountBorrowed, address receiver) public { + vm.assume(receiver != address(blue)); amountLent = bound(amountLent, 1, 2 ** 64); amountBorrowed = bound(amountBorrowed, 1, amountLent); @@ -371,6 +372,7 @@ contract BlueTest is Test { } function testWithdrawReceiver(uint256 amountLent, uint256 amountWithdrawn, address receiver) public { + vm.assume(receiver != address(blue)); amountLent = bound(amountLent, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, amountLent); @@ -505,6 +507,7 @@ contract BlueTest is Test { } function testWithdrawCollateral(uint256 amountDeposited, uint256 amountWithdrawn, address receiver) public { + vm.assume(receiver != address(blue)); amountDeposited = bound(amountDeposited, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, amountDeposited); From 971f043cc889bf1e76eb090d67dee25c387eb8b0 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Sat, 29 Jul 2023 13:26:43 +0200 Subject: [PATCH 5/9] refactor: transferOwnership -> setOwner --- src/Blue.sol | 2 +- test/forge/Blue.t.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Blue.sol b/src/Blue.sol index 627cb3960..dd5352d7d 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -73,7 +73,7 @@ contract Blue is IFlashLender { // Only owner functions. - function transferOwnership(address newOwner) external onlyOwner { + function setOwner(address newOwner) external onlyOwner { owner = newOwner; } diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index df02e303e..826484629 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -135,7 +135,7 @@ contract BlueTest is Blue blue2 = new Blue(oldOwner); vm.prank(oldOwner); - blue2.transferOwnership(newOwner); + blue2.setOwner(newOwner); assertEq(blue2.owner(), newOwner, "owner"); } @@ -146,7 +146,7 @@ contract BlueTest is vm.prank(attacker); vm.expectRevert(bytes(Errors.NOT_OWNER)); - blue2.transferOwnership(newOwner); + blue2.setOwner(newOwner); } function testEnableIrmWhenNotOwner(address attacker, IIrm newIrm) public { From 8e538da8e12568b694ad737571022ee5f6a8125b Mon Sep 17 00:00:00 2001 From: Rubilmax Date: Mon, 31 Jul 2023 11:24:42 +0200 Subject: [PATCH 6/9] test(forge): merge receiver tests --- test/forge/Blue.t.sol | 67 +++++++------------------------------------ 1 file changed, 10 insertions(+), 57 deletions(-) diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index 09a62ddc8..dc0864d06 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -314,7 +314,7 @@ contract BlueTest is assertEq(borrowableAsset.balanceOf(address(blue)), amount, "blue balance"); } - function testBorrow(uint256 amountLent, uint256 amountBorrowed) public { + function testBorrow(uint256 amountLent, uint256 amountBorrowed, address receiver) public { amountLent = bound(amountLent, 1, 2 ** 64); amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); @@ -324,26 +324,10 @@ contract BlueTest is if (amountBorrowed > amountLent) { vm.prank(BORROWER); vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); + blue.borrow(market, amountBorrowed, BORROWER, receiver); return; } - vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - - assertEq(blue.borrowShare(id, BORROWER), amountBorrowed * SharesMath.VIRTUAL_SHARES, "borrow share"); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "BORROWER balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed, "blue balance"); - } - - function testBorrowReceiver(uint256 amountLent, uint256 amountBorrowed, address receiver) public { - vm.assume(receiver != address(blue)); - amountLent = bound(amountLent, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, amountLent); - - borrowableAsset.setBalance(address(this), amountLent); - blue.supply(market, amountLent, address(this), hex""); - vm.prank(BORROWER); blue.borrow(market, amountBorrowed, BORROWER, receiver); @@ -352,7 +336,9 @@ contract BlueTest is assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed, "blue balance"); } - function testWithdraw(uint256 amountLent, uint256 amountWithdrawn, uint256 amountBorrowed) public { + function testWithdraw(uint256 amountLent, uint256 amountWithdrawn, uint256 amountBorrowed, address receiver) + public + { amountLent = bound(amountLent, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, 2 ** 64); amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); @@ -370,11 +356,11 @@ contract BlueTest is } else { vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); } - blue.withdraw(market, amountWithdrawn, address(this), address(this)); + blue.withdraw(market, amountWithdrawn, address(this), receiver); return; } - blue.withdraw(market, amountWithdrawn, address(this), address(this)); + blue.withdraw(market, amountWithdrawn, address(this), receiver); assertApproxEqAbs( blue.supplyShare(id, address(this)), @@ -382,31 +368,12 @@ contract BlueTest is 100, "supply share" ); - assertEq(borrowableAsset.balanceOf(address(this)), amountWithdrawn, "this balance"); + assertEq(borrowableAsset.balanceOf(receiver), amountWithdrawn, "receiver balance"); assertEq( borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed - amountWithdrawn, "blue balance" ); } - function testWithdrawReceiver(uint256 amountLent, uint256 amountWithdrawn, address receiver) public { - vm.assume(receiver != address(blue)); - amountLent = bound(amountLent, 1, 2 ** 64); - amountWithdrawn = bound(amountWithdrawn, 1, amountLent); - - borrowableAsset.setBalance(address(this), amountLent); - blue.supply(market, amountLent, address(this), hex""); - blue.withdraw(market, amountWithdrawn, address(this), receiver); - - assertApproxEqAbs( - blue.supplyShare(id, address(this)), - (amountLent - amountWithdrawn) * SharesMath.VIRTUAL_SHARES, - 100, - "supply share" - ); - assertEq(borrowableAsset.balanceOf(receiver), amountWithdrawn, "receiver balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountWithdrawn, "blue balance"); - } - function testCollateralRequirements( uint256 amountCollateral, uint256 amountBorrowed, @@ -503,7 +470,7 @@ contract BlueTest is assertEq(collateralAsset.balanceOf(address(blue)), amount, "blue balance"); } - function testWithdrawCollateral(uint256 amountDeposited, uint256 amountWithdrawn) public { + function testWithdrawCollateral(uint256 amountDeposited, uint256 amountWithdrawn, address receiver) public { amountDeposited = bound(amountDeposited, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, 2 ** 64); @@ -512,24 +479,10 @@ contract BlueTest is if (amountWithdrawn > amountDeposited) { vm.expectRevert(stdError.arithmeticError); - blue.withdrawCollateral(market, amountWithdrawn, address(this), address(this)); + blue.withdrawCollateral(market, amountWithdrawn, address(this), receiver); return; } - blue.withdrawCollateral(market, amountWithdrawn, address(this), address(this)); - - assertEq(blue.collateral(id, address(this)), amountDeposited - amountWithdrawn, "this collateral"); - assertEq(collateralAsset.balanceOf(address(this)), amountWithdrawn, "this balance"); - assertEq(collateralAsset.balanceOf(address(blue)), amountDeposited - amountWithdrawn, "blue balance"); - } - - function testWithdrawCollateral(uint256 amountDeposited, uint256 amountWithdrawn, address receiver) public { - vm.assume(receiver != address(blue)); - amountDeposited = bound(amountDeposited, 1, 2 ** 64); - amountWithdrawn = bound(amountWithdrawn, 1, amountDeposited); - - collateralAsset.setBalance(address(this), amountDeposited); - blue.supplyCollateral(market, amountDeposited, address(this), hex""); blue.withdrawCollateral(market, amountWithdrawn, address(this), receiver); assertEq(blue.collateral(id, address(this)), amountDeposited - amountWithdrawn, "this collateral"); From aec6b4e25245e7e08f118c17b6977db04048ec33 Mon Sep 17 00:00:00 2001 From: Rubilmax Date: Mon, 31 Jul 2023 11:55:04 +0200 Subject: [PATCH 7/9] test(forge): assume receiver not blue --- test/forge/Blue.t.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index dc0864d06..766ae2236 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -315,6 +315,7 @@ contract BlueTest is } function testBorrow(uint256 amountLent, uint256 amountBorrowed, address receiver) public { + vm.assume(receiver != address(blue)); amountLent = bound(amountLent, 1, 2 ** 64); amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); @@ -339,6 +340,7 @@ contract BlueTest is function testWithdraw(uint256 amountLent, uint256 amountWithdrawn, uint256 amountBorrowed, address receiver) public { + vm.assume(receiver != address(blue)); amountLent = bound(amountLent, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, 2 ** 64); amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); @@ -471,6 +473,7 @@ contract BlueTest is } function testWithdrawCollateral(uint256 amountDeposited, uint256 amountWithdrawn, address receiver) public { + vm.assume(receiver != address(blue)); amountDeposited = bound(amountDeposited, 1, 2 ** 64); amountWithdrawn = bound(amountWithdrawn, 1, 2 ** 64); From 1e28a92805fb17af225aeb92b3afdd1188dd54f7 Mon Sep 17 00:00:00 2001 From: makcandrov Date: Mon, 31 Jul 2023 05:17:27 -0700 Subject: [PATCH 8/9] style: remove early return --- src/Blue.sol | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Blue.sol b/src/Blue.sol index 0bd41c87e..1fd5ae259 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -290,26 +290,26 @@ contract Blue is IFlashLender { function _accrueInterests(Market memory market, Id id) internal { uint256 elapsed = block.timestamp - lastUpdate[id]; - if (elapsed == 0) return; - - uint256 marketTotalBorrow = totalBorrow[id]; - - if (marketTotalBorrow != 0) { - uint256 borrowRate = market.irm.borrowRate(market); - uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate * elapsed); - totalBorrow[id] = marketTotalBorrow + accruedInterests; - totalSupply[id] += accruedInterests; - - if (fee[id] != 0) { - uint256 feeAmount = accruedInterests.mulWadDown(fee[id]); - // The fee amount is subtracted from the total supply in this calculation to compensate for the fact that total supply is already updated. - uint256 feeShares = feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount); - supplyShare[id][feeRecipient] += feeShares; - totalSupplyShares[id] += feeShares; + if (elapsed != 0) { + uint256 marketTotalBorrow = totalBorrow[id]; + + if (marketTotalBorrow != 0) { + uint256 borrowRate = market.irm.borrowRate(market); + uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate * elapsed); + totalBorrow[id] = marketTotalBorrow + accruedInterests; + totalSupply[id] += accruedInterests; + + if (fee[id] != 0) { + uint256 feeAmount = accruedInterests.mulWadDown(fee[id]); + // The fee amount is subtracted from the total supply in this calculation to compensate for the fact that total supply is already updated. + uint256 feeShares = feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount); + supplyShare[id][feeRecipient] += feeShares; + totalSupplyShares[id] += feeShares; + } } - } - lastUpdate[id] = block.timestamp; + lastUpdate[id] = block.timestamp; + } } // Health check. From f5f40d2bae889b160c48790177c9025abed1f479 Mon Sep 17 00:00:00 2001 From: makcandrov Date: Mon, 31 Jul 2023 06:40:23 -0700 Subject: [PATCH 9/9] Revert "style: remove early return" This reverts commit 1e28a92805fb17af225aeb92b3afdd1188dd54f7. --- src/Blue.sol | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Blue.sol b/src/Blue.sol index e5fc6f33e..208e3f43f 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -290,26 +290,26 @@ contract Blue is IFlashLender { function _accrueInterests(Market memory market, Id id) internal { uint256 elapsed = block.timestamp - lastUpdate[id]; - if (elapsed != 0) { - uint256 marketTotalBorrow = totalBorrow[id]; - - if (marketTotalBorrow != 0) { - uint256 borrowRate = market.irm.borrowRate(market); - uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate * elapsed); - totalBorrow[id] = marketTotalBorrow + accruedInterests; - totalSupply[id] += accruedInterests; - - if (fee[id] != 0) { - uint256 feeAmount = accruedInterests.mulWadDown(fee[id]); - // The fee amount is subtracted from the total supply in this calculation to compensate for the fact that total supply is already updated. - uint256 feeShares = feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount); - supplyShare[id][feeRecipient] += feeShares; - totalSupplyShares[id] += feeShares; - } + if (elapsed == 0) return; + + uint256 marketTotalBorrow = totalBorrow[id]; + + if (marketTotalBorrow != 0) { + uint256 borrowRate = market.irm.borrowRate(market); + uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate * elapsed); + totalBorrow[id] = marketTotalBorrow + accruedInterests; + totalSupply[id] += accruedInterests; + + if (fee[id] != 0) { + uint256 feeAmount = accruedInterests.mulWadDown(fee[id]); + // The fee amount is subtracted from the total supply in this calculation to compensate for the fact that total supply is already updated. + uint256 feeShares = feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount); + supplyShare[id][feeRecipient] += feeShares; + totalSupplyShares[id] += feeShares; } - - lastUpdate[id] = block.timestamp; } + + lastUpdate[id] = block.timestamp; } // Health check.