diff --git a/test/forge/BlueBase.t.sol b/test/forge/BlueBase.t.sol deleted file mode 100644 index 271f710c2..000000000 --- a/test/forge/BlueBase.t.sol +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "forge-std/Test.sol"; -import "forge-std/console.sol"; - -import "src/Blue.sol"; -import {ERC20Mock as ERC20} from "src/mocks/ERC20Mock.sol"; -import {OracleMock as Oracle} from "src/mocks/OracleMock.sol"; -import {IrmMock as Irm} from "src/mocks/IrmMock.sol"; - -contract BlueBaseTest is Test { - using FixedPointMathLib for uint256; - - address internal constant BORROWER = address(1234); - address internal constant LIQUIDATOR = address(5678); - uint256 internal constant LLTV = 0.8 ether; - address internal constant OWNER = address(0xdead); - - Blue internal blue; - ERC20 internal borrowableAsset; - ERC20 internal collateralAsset; - Oracle internal borrowableOracle; - Oracle internal collateralOracle; - Irm internal irm; - Market public market; - Id public id; - - function setUp() public { - // Create Blue. - blue = new Blue(OWNER); - - // List a market. - borrowableAsset = new ERC20("borrowable", "B", 18); - collateralAsset = new ERC20("collateral", "C", 18); - borrowableOracle = new Oracle(); - collateralOracle = new Oracle(); - - irm = new Irm(blue); - market = Market( - address(borrowableAsset), - address(collateralAsset), - address(borrowableOracle), - address(collateralOracle), - address(irm), - LLTV - ); - id = Id.wrap(keccak256(abi.encode(market))); - - vm.startPrank(OWNER); - blue.enableIrm(address(irm)); - blue.enableLltv(LLTV); - blue.createMarket(market); - vm.stopPrank(); - - // We set the price of the borrowable asset to zero so that borrowers - // don't need to deposit any collateral. - borrowableOracle.setPrice(0); - collateralOracle.setPrice(1e18); - - borrowableAsset.approve(address(blue), type(uint256).max); - collateralAsset.approve(address(blue), type(uint256).max); - vm.startPrank(BORROWER); - borrowableAsset.approve(address(blue), type(uint256).max); - collateralAsset.approve(address(blue), type(uint256).max); - vm.stopPrank(); - vm.startPrank(LIQUIDATOR); - borrowableAsset.approve(address(blue), type(uint256).max); - collateralAsset.approve(address(blue), type(uint256).max); - vm.stopPrank(); - } - - function netWorth(address user) internal view returns (uint256) { - uint256 collateralAssetValue = collateralAsset.balanceOf(user).mulWadDown(collateralOracle.price()); - uint256 borrowableAssetValue = borrowableAsset.balanceOf(user).mulWadDown(borrowableOracle.price()); - return collateralAssetValue + borrowableAssetValue; - } - - function supplyBalance(address user) internal view returns (uint256) { - uint256 supplyShares = blue.supplyShares(id, user); - if (supplyShares == 0) return 0; - - uint256 totalShares = blue.totalSupplyShares(id); - uint256 totalSupply = blue.totalSupply(id); - return supplyShares.divWadDown(totalShares).mulWadDown(totalSupply); - } - - function borrowBalance(address user) internal view returns (uint256) { - uint256 borrowerShares = blue.borrowShares(id, user); - if (borrowerShares == 0) return 0; - - uint256 totalShares = blue.totalBorrowShares(id); - uint256 totalBorrow = blue.totalBorrow(id); - return borrowerShares.divWadUp(totalShares).mulWadUp(totalBorrow); - } - - function neq(Market memory a, Market memory b) internal pure returns (bool) { - return a.borrowableAsset != b.borrowableAsset || a.collateralAsset != b.collateralAsset - || a.borrowableOracle != b.borrowableOracle || a.collateralOracle != b.collateralOracle || a.lltv != b.lltv - || a.irm != b.irm; - } -} diff --git a/test/forge/integration/TestIntegrationBorrow.sol b/test/forge/integration/TestIntegrationBorrow.sol deleted file mode 100644 index 2e3273229..000000000 --- a/test/forge/integration/TestIntegrationBorrow.sol +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationBorrowTest is BlueBaseTest { - using FixedPointMathLib for uint256; - - function testBorrowUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.borrow(marketFuzz, 1, address(this), address(this)); - } - - function testBorrowZeroAmount() public { - vm.prank(BORROWER); - - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.borrow(market, 0, address(this), address(this)); - } - - function testBorrowToZeroAddress() public { - vm.prank(BORROWER); - - vm.expectRevert(bytes(Errors.ZERO_ADDRESS)); - blue.borrow(market, 1, BORROWER, address(0)); - } - - - function testBorrowUnauthorized(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - borrowableAsset.setBalance(address(this), amount); - blue.supply(market, amount, address(this), hex""); - - vm.prank(BORROWER); - vm.expectRevert(bytes(Errors.UNAUTHORIZED)); - blue.borrow(market, amount, address(this), BORROWER); - } - - function testBorrowUnhealthyPosition( - uint256 amountCollateral, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 0, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 0, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - < amountBorrowed.mulWadUp(priceBorrowable) - ); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountBorrowed); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountBorrowed, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - vm.expectRevert(bytes(Errors.INSUFFICIENT_COLLATERAL)); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.stopPrank(); - } - - function testBorrowUnsufficientLiquidity( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 0, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 0, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied < amountBorrowed); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.stopPrank(); - } - - function testBorrow( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 0, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 0, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.stopPrank(); - - assertEq(blue.totalBorrow(id), amountBorrowed, "total borrow"); - assertEq(blue.borrowShares(id, BORROWER), amountBorrowed * SharesMath.VIRTUAL_SHARES, "borrow shares"); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "borrower balance"); - assertEq(borrowableAsset.balanceOf(address(this)), 0, "lender balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amountSupplied - amountBorrowed, "blue balance"); - } - - function testBorrowOnBehalf( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 0, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 0, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - collateralAsset.setBalance(address(this), amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - blue.supplyCollateral(market, amountCollateral, address(this), hex""); - blue.setAuthorization(BORROWER, true); - - vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, address(this), address(this)); - - assertEq(blue.totalBorrow(id), amountBorrowed, "total borrow"); - assertEq(blue.borrowShares(id, address(this)), amountBorrowed * SharesMath.VIRTUAL_SHARES, "borrow shares"); - assertEq(borrowableAsset.balanceOf(BORROWER), 0, "borrower balance"); - assertEq(borrowableAsset.balanceOf(address(this)), amountBorrowed, "lender balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amountSupplied - amountBorrowed, "blue balance"); - } -} diff --git a/test/forge/integration/TestIntegrationCreateMarket.sol b/test/forge/integration/TestIntegrationCreateMarket.sol deleted file mode 100644 index 661dc3cbf..000000000 --- a/test/forge/integration/TestIntegrationCreateMarket.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationCreateMarketTest is BlueBaseTest { - using MarketLib for Market; - using FixedPointMathLib for uint256; - - function testCreateMarketWithNotEnabledIrm(Market memory marketFuzz) public { - vm.assume(marketFuzz.irm != address(irm)); - - vm.prank(OWNER); - vm.expectRevert(bytes(Errors.IRM_NOT_ENABLED)); - blue.createMarket(marketFuzz); - } - - function testCreateMarketWithEnabledIrmAndNotEnabledLLTV(Market memory marketFuzz) public { - vm.assume(marketFuzz.lltv != LLTV); - - vm.startPrank(OWNER); - blue.enableIrm(marketFuzz.irm); - vm.expectRevert(bytes(Errors.LLTV_NOT_ENABLED)); - blue.createMarket(marketFuzz); - vm.stopPrank(); - } - - function testCreateMarketWithEnabledIrmAndLLTV(Market memory marketFuzz) public { - marketFuzz.lltv = LLTV; - Id marketFuzzId = marketFuzz.id(); - - vm.prank(OWNER); - blue.enableIrm(marketFuzz.irm); - blue.createMarket(marketFuzz); - - assertGt(blue.lastUpdate(marketFuzzId), 0, "lastUpdate == 0"); - assertEq(blue.totalSupply(marketFuzzId), 0, "totalSupply != 0"); - assertEq(blue.totalSupplyShares(marketFuzzId), 0, "totalSupplyShares != 0"); - assertEq(blue.totalBorrow(marketFuzzId), 0, "totalBorrow != 0"); - assertEq(blue.totalBorrowShares(marketFuzzId), 0, "totalBorrowShares != 0"); - assertEq(blue.fee(marketFuzzId), 0, "fee != 0"); - } -} diff --git a/test/forge/integration/TestIntegrationLiquidate.sol b/test/forge/integration/TestIntegrationLiquidate.sol deleted file mode 100644 index 10c25ba86..000000000 --- a/test/forge/integration/TestIntegrationLiquidate.sol +++ /dev/null @@ -1,213 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationLiquidateTest is BlueBaseTest { - using FixedPointMathLib for uint256; - using SharesMath for uint256; - - function testLiquidateUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.liquidate(marketFuzz, address(this), 1, hex""); - } - - function testLiquidateZeroAmount() public { - vm.prank(BORROWER); - - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.liquidate(market, address(this), 0, hex""); - } - - function testLiquidateHealthyPosition( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 amountSeized, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - amountSeized = bound(amountSeized, 1, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 0, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 0, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - vm.assume(amountCollateral >= amountSeized); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - borrowableAsset.setBalance(LIQUIDATOR, amountBorrowed); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.stopPrank(); - - vm.prank(LIQUIDATOR); - vm.expectRevert(bytes(Errors.HEALTHY_POSITION)); - blue.liquidate(market, BORROWER, amountSeized, hex""); - } - - function testLiquidateNoBadDebt( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 amountSeized, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - amountSeized = bound(amountSeized, 1, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 1, 2 ** 64); - - uint256 incentive = FixedPointMathLib.WAD - + ALPHA.mulWadDown(FixedPointMathLib.WAD.divWadDown(market.lltv) - FixedPointMathLib.WAD); - uint256 expectedRepaid = amountSeized.mulWadUp(priceCollateral).divWadUp(incentive).divWadUp(priceBorrowable); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) + 2 - < amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - vm.assume(expectedRepaid < amountBorrowed && amountSeized < amountCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - borrowableAsset.setBalance(LIQUIDATOR, amountBorrowed); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.stopPrank(); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - uint256 expectedRepaidShares = expectedRepaid.toSharesDown(blue.totalBorrow(id), blue.totalBorrowShares(id)); - - vm.prank(LIQUIDATOR); - blue.liquidate(market, BORROWER, amountSeized, hex""); - - assertEq( - blue.borrowShares(id, BORROWER), - amountBorrowed * SharesMath.VIRTUAL_SHARES - expectedRepaidShares, - "borrow share" - ); - assertEq(blue.totalBorrow(id), amountBorrowed - expectedRepaid, "borrow shares"); - assertEq(blue.collateral(id, BORROWER), amountCollateral - amountSeized, "collateral"); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "borrower balance"); - assertEq(borrowableAsset.balanceOf(LIQUIDATOR), amountBorrowed - expectedRepaid, "liquidator balance"); - assertEq( - borrowableAsset.balanceOf(address(blue)), amountSupplied - amountBorrowed + expectedRepaid, "blue balance" - ); - assertEq(collateralAsset.balanceOf(address(blue)), amountCollateral - amountSeized, "blue collateral balance"); - assertEq(collateralAsset.balanceOf(LIQUIDATOR), amountSeized, "blue collateral balance"); - } - - struct LiquidateBadDebtTestParams { - uint256 incentive; - uint256 expectedRepaid; - uint256 expectedRepaidShares; - uint256 borrowSharesBeforeLiquidation; - uint256 totalBorrowSharesBeforeLiquidation; - uint256 totalBorrowBeforeLiquidation; - uint256 totalSupplyBeforeLiquidation; - uint256 expectedBadDebt; - } - - function testLiquidateBadDebt( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - LiquidateBadDebtTestParams memory params; - - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 1, 2 ** 64); - - params.incentive = FixedPointMathLib.WAD - + ALPHA.mulWadDown(FixedPointMathLib.WAD.divWadDown(market.lltv) - FixedPointMathLib.WAD); - params.expectedRepaid = - amountCollateral.mulWadUp(priceCollateral).divWadUp(params.incentive).divWadUp(priceBorrowable); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) + 2 - < amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - vm.assume(params.expectedRepaid < amountBorrowed); - - borrowableAsset.setBalance(address(this), amountSupplied); - borrowableAsset.setBalance(LIQUIDATOR, amountBorrowed); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.stopPrank(); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - params.expectedRepaidShares = - params.expectedRepaid.toSharesDown(blue.totalBorrow(id), blue.totalBorrowShares(id)); - params.borrowSharesBeforeLiquidation = blue.borrowShares(id, BORROWER); - params.totalBorrowSharesBeforeLiquidation = blue.totalBorrowShares(id); - params.totalBorrowBeforeLiquidation = blue.totalBorrow(id); - params.totalSupplyBeforeLiquidation = blue.totalSupply(id); - params.expectedBadDebt = (params.borrowSharesBeforeLiquidation - params.expectedRepaidShares).toAssetsUp( - params.totalBorrowBeforeLiquidation - params.expectedRepaid, - params.totalBorrowSharesBeforeLiquidation - params.expectedRepaidShares - ); - - vm.prank(LIQUIDATOR); - blue.liquidate(market, BORROWER, amountCollateral, hex""); - - assertEq(blue.collateral(id, BORROWER), 0, "collateral"); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "borrower balance"); - assertEq(borrowableAsset.balanceOf(LIQUIDATOR), amountBorrowed - params.expectedRepaid, "liquidator balance"); - assertEq( - borrowableAsset.balanceOf(address(blue)), - amountSupplied - amountBorrowed + params.expectedRepaid, - "blue balance" - ); - assertEq(collateralAsset.balanceOf(address(blue)), 0, "blue collateral balance"); - assertEq(collateralAsset.balanceOf(LIQUIDATOR), amountCollateral, "blue collateral balance"); - - //bad debt realisation - assertEq(blue.borrowShares(id, BORROWER), 0, "borrow sharse"); - assertEq(blue.totalBorrowShares(id), 0, "total borrow shares"); - assertEq( - blue.totalBorrow(id), - params.totalBorrowBeforeLiquidation - params.expectedRepaid - params.expectedBadDebt, - "total borrow" - ); - assertEq(blue.totalSupply(id), params.totalSupplyBeforeLiquidation - params.expectedBadDebt, "total borrow"); - } -} diff --git a/test/forge/integration/TestIntegrationOnlyOwner.sol b/test/forge/integration/TestIntegrationOnlyOwner.sol deleted file mode 100644 index d3c0c8b10..000000000 --- a/test/forge/integration/TestIntegrationOnlyOwner.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationOnlyOwnerTest is BlueBaseTest { - using MarketLib for Market; - using FixedPointMathLib for uint256; - - function testSetOwnerWhenNotOwner(address addressFuzz) public { - vm.assume(addressFuzz != OWNER); - - vm.prank(addressFuzz); - vm.expectRevert(bytes(Errors.NOT_OWNER)); - blue.setOwner(addressFuzz); - } - - function testSetOwner(address newOwner) public { - vm.assume(newOwner != OWNER); - - vm.prank(OWNER); - blue.setOwner(newOwner); - - assertEq(blue.owner(), newOwner, "owner is not set"); - } - - function testEnableIrmWhenNotOwner(address addressFuzz, address irmFuzz) public { - vm.assume(addressFuzz != OWNER); - vm.assume(irmFuzz != address(irm)); - - vm.prank(addressFuzz); - vm.expectRevert(bytes(Errors.NOT_OWNER)); - blue.enableIrm(irmFuzz); - } - - function testEnableIrm(address irmFuzz) public { - vm.assume(irmFuzz != address(irm)); - - vm.prank(OWNER); - blue.enableIrm(irmFuzz); - - assertTrue(blue.isIrmEnabled(irmFuzz), "IRM is not enabled"); - } - - function testEnableLLTVWhenNotOwner(address addressFuzz, uint256 lltvFuzz) public { - vm.assume(addressFuzz != OWNER); - vm.assume(lltvFuzz != LLTV); - - vm.prank(addressFuzz); - vm.expectRevert(bytes(Errors.NOT_OWNER)); - blue.enableLltv(lltvFuzz); - } - - function testEnableTooHighLLTV(uint256 lltvFuzz) public { - lltvFuzz = bound(lltvFuzz, FixedPointMathLib.WAD, type(uint256).max); - - vm.prank(OWNER); - vm.expectRevert(bytes(Errors.LLTV_TOO_HIGH)); - blue.enableLltv(lltvFuzz); - } - - function testEnableLLTV(uint256 lltvFuzz) public { - lltvFuzz = bound(lltvFuzz, 0, FixedPointMathLib.WAD - 1); - - vm.prank(OWNER); - blue.enableLltv(lltvFuzz); - - assertTrue(blue.isLltvEnabled(lltvFuzz), "LLTV is not enabled"); - } - - function testSetFeeWhenNotOwner(address addressFuzz, uint256 feeFuzz) public { - vm.assume(addressFuzz != OWNER); - - vm.prank(addressFuzz); - vm.expectRevert(bytes(Errors.NOT_OWNER)); - blue.setFee(market, feeFuzz); - } - - function testSetFeeWhenMarketNotCreated(Market memory marketFuzz, uint256 feeFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.prank(OWNER); - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.setFee(marketFuzz, feeFuzz); - } - - function testSetTooHighFee(uint256 feeFuzz) public { - feeFuzz = bound(feeFuzz, MAX_FEE + 1, type(uint256).max); - - vm.prank(OWNER); - vm.expectRevert(bytes(Errors.MAX_FEE_EXCEEDED)); - blue.setFee(market, feeFuzz); - } - - function testSetFee(uint256 feeFuzz) public { - feeFuzz = bound(feeFuzz, 0, MAX_FEE); - - vm.prank(OWNER); - blue.setFee(market, feeFuzz); - - assertEq(blue.fee(id), feeFuzz); - } - - function testSetFeeRecipientWhenNotOwner(address addressFuzz) public { - vm.assume(addressFuzz != OWNER); - - vm.prank(addressFuzz); - vm.expectRevert(bytes(Errors.NOT_OWNER)); - blue.setFeeRecipient(addressFuzz); - } - - function testSetFeeRecipient(address newFeeRecipient) public { - vm.assume(newFeeRecipient != OWNER); - - vm.prank(OWNER); - blue.setFeeRecipient(newFeeRecipient); - - assertEq(blue.feeRecipient(), newFeeRecipient); - } -} diff --git a/test/forge/integration/TestIntegrationRepay.sol b/test/forge/integration/TestIntegrationRepay.sol deleted file mode 100644 index c7441aa98..000000000 --- a/test/forge/integration/TestIntegrationRepay.sol +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationRepayTest is BlueBaseTest { - function testRepayUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.repay(marketFuzz, 1, address(this), hex""); - } - - function testRepayZeroAmount() public { - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.repay(market, 0, address(this), hex""); - } - - function testRepayOnBehalfZeroAddress() public { - vm.expectRevert(bytes(Errors.ZERO_ADDRESS)); - blue.repay(market, 1, address(0), hex""); - } - - function testRepay(uint256 amountLent, uint256 amountBorrowed, uint256 amountRepaid) public { - amountLent = bound(amountLent, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, amountLent); - amountRepaid = bound(amountRepaid, 1, amountBorrowed); - - borrowableAsset.setBalance(address(this), amountLent); - blue.supply(market, amountLent, address(this), hex""); - - vm.startPrank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - blue.repay(market, amountRepaid, BORROWER, hex""); - vm.stopPrank(); - - assertEq(blue.totalBorrow(id), amountBorrowed - amountRepaid, "total borrow"); - assertApproxEqAbs( - blue.borrowShares(id, BORROWER), - (amountBorrowed - amountRepaid) * SharesMath.VIRTUAL_SHARES, - 100, - "borrow shares" - ); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed - amountRepaid, "BORROWER balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed + amountRepaid, "blue balance"); - } - - function testRepayOnBehalf(uint256 amountLent, uint256 amountBorrowed, uint256 amountRepaid) public { - amountLent = bound(amountLent, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, amountLent); - amountRepaid = bound(amountRepaid, 1, amountBorrowed); - - borrowableAsset.setBalance(address(this), amountLent + amountRepaid); - blue.supply(market, amountLent, address(this), hex""); - - vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - blue.repay(market, amountRepaid, BORROWER, hex""); - - assertEq(blue.totalBorrow(id), amountBorrowed - amountRepaid, "total borrow"); - assertApproxEqAbs( - blue.borrowShares(id, BORROWER), - (amountBorrowed - amountRepaid) * SharesMath.VIRTUAL_SHARES, - 100, - "borrow shares" - ); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "BORROWER balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amountLent - amountBorrowed + amountRepaid, "blue balance"); - } -} \ No newline at end of file diff --git a/test/forge/integration/TestIntegrationSupply.sol b/test/forge/integration/TestIntegrationSupply.sol deleted file mode 100644 index 46e172c87..000000000 --- a/test/forge/integration/TestIntegrationSupply.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationSupplyTest is BlueBaseTest { - function testSupplyUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.supply(marketFuzz, 1, address(this), hex""); - } - - function testSupplyZeroAmount() public { - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.supply(market, 0, address(this), hex""); - } - - function testSupplyOnBehalfZeroAddress() public { - vm.expectRevert(bytes(Errors.ZERO_ADDRESS)); - blue.supply(market, 1, address(0), hex""); - } - - function testSupply(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - borrowableAsset.setBalance(address(this), amount); - blue.supply(market, amount, address(this), hex""); - - assertEq(blue.totalSupply(id), amount, "total supply"); - assertEq(blue.supplyShares(id, address(this)), amount * SharesMath.VIRTUAL_SHARES, "supply shares"); - assertEq(borrowableAsset.balanceOf(address(this)), 0, "lender balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amount, "blue balance"); - } - - function testSupplyOnBehalf(uint256 amount, address onBehalf) public { - vm.assume(onBehalf != address(blue) && onBehalf != address(0)); - amount = bound(amount, 1, 2 ** 64); - - borrowableAsset.setBalance(address(this), amount); - blue.supply(market, amount, onBehalf, hex""); - - assertEq(blue.totalSupply(id), amount, "total supply"); - assertEq(blue.supplyShares(id, onBehalf), amount * SharesMath.VIRTUAL_SHARES, "supply shares"); - assertEq(borrowableAsset.balanceOf(onBehalf), 0, "lender balance"); - assertEq(borrowableAsset.balanceOf(address(blue)), amount, "blue balance"); - } -} diff --git a/test/forge/integration/TestIntegrationSupplyCollateral.sol b/test/forge/integration/TestIntegrationSupplyCollateral.sol deleted file mode 100644 index a00fac0df..000000000 --- a/test/forge/integration/TestIntegrationSupplyCollateral.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationSupplyCollateralTest is BlueBaseTest { - function testSupplyCollateralUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.supply(marketFuzz, 1, address(this), hex""); - } - - function testSupplyCollateralZeroAmount() public { - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.supplyCollateral(market, 0, address(this), hex""); - } - - function testSupplyCollateralOnBehalfZeroAddress() public { - vm.expectRevert(bytes(Errors.ZERO_ADDRESS)); - blue.supplyCollateral(market, 1, address(0), hex""); - } - - function testSupplyCollateral(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - collateralAsset.setBalance(address(this), amount); - blue.supplyCollateral(market, amount, address(this), hex""); - - assertEq(blue.collateral(id, address(this)), amount, "collateral balance"); - assertEq(collateralAsset.balanceOf(address(this)), 0, "lender balance"); - assertEq(collateralAsset.balanceOf(address(blue)), amount, "blue balance"); - } - - function testSupplyCollateralOnBehalf(uint256 amount, address onBehalf) public { - vm.assume(onBehalf != address(blue) && onBehalf != address(0)); - amount = bound(amount, 1, 2 ** 64); - - collateralAsset.setBalance(address(this), amount); - blue.supplyCollateral(market, amount, onBehalf, hex""); - - assertEq(blue.collateral(id, onBehalf), amount, "collateral balance"); - assertEq(collateralAsset.balanceOf(onBehalf), 0, "lender balance"); - assertEq(collateralAsset.balanceOf(address(blue)), amount, "blue balance"); - } -} diff --git a/test/forge/integration/TestIntegrationWithdraw.sol b/test/forge/integration/TestIntegrationWithdraw.sol deleted file mode 100644 index 220029707..000000000 --- a/test/forge/integration/TestIntegrationWithdraw.sol +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationWithdrawTest is BlueBaseTest { - function testWithdrawUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.withdraw(marketFuzz, 1, address(this), address(this)); - } - - function testWithdrawZeroAmount(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - borrowableAsset.setBalance(address(this), amount); - blue.supply(market, amount, address(this), hex""); - - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.withdraw(market, 0, address(this), address(this)); - } - - function testWithdrawToZeroAddress(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - borrowableAsset.setBalance(address(this), amount); - blue.supply(market, amount, address(this), hex""); - - vm.expectRevert(bytes(Errors.ZERO_ADDRESS)); - blue.withdraw(market, amount, address(this), address(0)); - } - - function testWithdrawUnauthorized(address attacker, uint256 amount) public { - vm.assume(attacker != address(this)); - amount = bound(amount, 1, 2 ** 64); - - borrowableAsset.setBalance(address(this), amount); - blue.supply(market, amount, address(this), hex""); - - vm.prank(attacker); - vm.expectRevert(bytes(Errors.UNAUTHORIZED)); - blue.withdraw(market, amount, address(this), address(this)); - } - - function testWithdrawUnsufficientLiquidity(uint256 amountSupplied, uint256 amountBorrowed) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, amountSupplied); - - borrowableAsset.setBalance(address(this), amountSupplied); - blue.supply(market, amountSupplied, address(this), hex""); - - vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - - vm.expectRevert(bytes(Errors.INSUFFICIENT_LIQUIDITY)); - blue.withdraw(market, amountSupplied, address(this), address(this)); - } - - function testWithdraw(uint256 amountSupplied, uint256 amountBorrowed, uint256 amountWithdrawn) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, amountSupplied); - amountWithdrawn = bound(amountWithdrawn, 1, amountSupplied); - vm.assume(amountWithdrawn <= amountSupplied - amountBorrowed); - - borrowableAsset.setBalance(address(this), amountSupplied); - blue.supply(market, amountSupplied, address(this), hex""); - - vm.prank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - - blue.withdraw(market, amountWithdrawn, address(this), address(this)); - - assertApproxEqAbs( - blue.supplyShares(id, address(this)), - (amountSupplied - amountWithdrawn) * SharesMath.VIRTUAL_SHARES, - 100, - "supply shares" - ); - assertEq(borrowableAsset.balanceOf(address(this)), amountWithdrawn, "this balance"); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed, "Borrower balance"); - assertEq( - borrowableAsset.balanceOf(address(blue)), amountSupplied - amountBorrowed - amountWithdrawn, "blue balance" - ); - } - - function testWithdrawOnBehalf( - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 amountWithdrawn, - uint256 amountWithdrawnToReceiver - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, amountSupplied); - amountWithdrawn = bound(amountWithdrawn, 1, amountSupplied); - amountWithdrawnToReceiver = bound(amountWithdrawnToReceiver, 1, amountSupplied); - vm.assume(amountWithdrawn + amountWithdrawnToReceiver <= amountSupplied - amountBorrowed); - - borrowableAsset.setBalance(address(this), amountSupplied); - blue.supply(market, amountSupplied, address(this), hex""); - blue.setAuthorization(BORROWER, true); - - vm.startPrank(BORROWER); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - - blue.withdraw(market, amountWithdrawn, address(this), BORROWER); - blue.withdraw(market, amountWithdrawnToReceiver, address(this), address(this)); - - vm.stopPrank(); - - assertEq(blue.totalSupply(id), amountSupplied - amountWithdrawn - amountWithdrawnToReceiver, "total supply"); - assertApproxEqAbs( - blue.supplyShares(id, address(this)), - (amountSupplied - amountWithdrawn - amountWithdrawnToReceiver) * SharesMath.VIRTUAL_SHARES, - 100, - "supply shares" - ); - assertEq(borrowableAsset.balanceOf(address(this)), amountWithdrawnToReceiver, "this balance"); - assertEq(borrowableAsset.balanceOf(BORROWER), amountBorrowed + amountWithdrawn, "Borrower balance"); - assertEq( - borrowableAsset.balanceOf(address(blue)), - amountSupplied - amountBorrowed - amountWithdrawn - amountWithdrawnToReceiver, - "blue balance" - ); - } -} diff --git a/test/forge/integration/TestIntegrationWithdrawCollateral.sol b/test/forge/integration/TestIntegrationWithdrawCollateral.sol deleted file mode 100644 index 065157452..000000000 --- a/test/forge/integration/TestIntegrationWithdrawCollateral.sol +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "test/forge/BlueBase.t.sol"; - -contract IntegrationWithdrawCollateralTest is BlueBaseTest { - using FixedPointMathLib for uint256; - - function testWithdrawCollateralUnknownMarket(Market memory marketFuzz) public { - vm.assume(neq(marketFuzz, market)); - - vm.expectRevert(bytes(Errors.MARKET_NOT_CREATED)); - blue.withdrawCollateral(marketFuzz, 1, address(this), address(this)); - } - - function testWithdrawCollateralZeroAmount(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - collateralAsset.setBalance(address(this), amount); - blue.supplyCollateral(market, amount, address(this), hex""); - - vm.expectRevert(bytes(Errors.ZERO_AMOUNT)); - blue.withdrawCollateral(market, 0, address(this), address(this)); - } - - function testWithdrawCollateralToZeroAddress(uint256 amount) public { - amount = bound(amount, 1, 2 ** 64); - - collateralAsset.setBalance(address(this), amount); - blue.supplyCollateral(market, amount, address(this), hex""); - - vm.expectRevert(bytes(Errors.ZERO_ADDRESS)); - blue.withdrawCollateral(market, amount, address(this), address(0)); - } - - function testWithdrawCollateralUnauthorized(address attacker, uint256 amount) public { - vm.assume(attacker != address(this)); - amount = bound(amount, 1, 2 ** 64); - - collateralAsset.setBalance(address(this), amount); - blue.supplyCollateral(market, amount, address(this), hex""); - - vm.prank(attacker); - vm.expectRevert(bytes(Errors.UNAUTHORIZED)); - blue.withdrawCollateral(market, amount, address(this), address(this)); - } - - function testWithdrawCollateralUnhealthyPosition( - uint256 amountCollateral, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 1, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 1, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - collateralAsset.setBalance(BORROWER, amountCollateral); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral, BORROWER, hex""); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - vm.expectRevert(bytes(Errors.INSUFFICIENT_COLLATERAL)); - blue.withdrawCollateral(market, amountCollateral, BORROWER, BORROWER); - vm.stopPrank(); - } - - function testWithdrawCollateral( - uint256 amountCollateral, - uint256 amountCollateralExcess, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 1, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - amountCollateralExcess = bound(amountCollateralExcess, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 1, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - collateralAsset.setBalance(BORROWER, amountCollateral + amountCollateralExcess); - - blue.supply(market, amountSupplied, address(this), hex""); - - vm.startPrank(BORROWER); - blue.supplyCollateral(market, amountCollateral + amountCollateralExcess, BORROWER, hex""); - blue.borrow(market, amountBorrowed, BORROWER, BORROWER); - blue.withdrawCollateral(market, amountCollateralExcess, BORROWER, BORROWER); - vm.stopPrank(); - - assertEq(blue.collateral(id, BORROWER), amountCollateral, "collateral balance"); - assertEq(collateralAsset.balanceOf(BORROWER), amountCollateralExcess, "lender balance"); - assertEq(collateralAsset.balanceOf(address(blue)), amountCollateral, "blue balance"); - } - - function testWithdrawCollateralOnBehalf( - uint256 amountCollateral, - uint256 amountCollateralExcess, - uint256 amountSupplied, - uint256 amountBorrowed, - uint256 priceCollateral, - uint256 priceBorrowable - ) public { - amountSupplied = bound(amountSupplied, 1, 2 ** 64); - amountBorrowed = bound(amountBorrowed, 1, 2 ** 64); - priceBorrowable = bound(priceBorrowable, 1, 2 ** 64); - amountCollateral = bound(amountCollateral, 1, 2 ** 64); - amountCollateralExcess = bound(amountCollateralExcess, 1, 2 ** 64); - priceCollateral = bound(priceCollateral, 1, 2 ** 64); - - vm.assume( - amountCollateral.mulWadDown(priceCollateral).mulWadDown(market.lltv) - >= amountBorrowed.mulWadUp(priceBorrowable) - ); - vm.assume(amountSupplied >= amountBorrowed); - - borrowableOracle.setPrice(priceBorrowable); - collateralOracle.setPrice(priceCollateral); - - borrowableAsset.setBalance(address(this), amountSupplied); - collateralAsset.setBalance(address(this), amountCollateral + amountCollateralExcess); - - blue.supply(market, amountSupplied, address(this), hex""); - blue.supplyCollateral(market, amountCollateral + amountCollateralExcess, address(this), hex""); - blue.borrow(market, amountBorrowed, address(this), address(this)); - blue.setAuthorization(BORROWER, true); - - vm.prank(BORROWER); - blue.withdrawCollateral(market, amountCollateralExcess, address(this), address(this)); - - assertEq(blue.collateral(id, address(this)), amountCollateral, "collateral balance"); - assertEq(collateralAsset.balanceOf(address(this)), amountCollateralExcess, "lender balance"); - assertEq(collateralAsset.balanceOf(BORROWER), 0, "lender balance"); - assertEq(collateralAsset.balanceOf(address(blue)), amountCollateral, "blue balance"); - } -}