Skip to content

Commit

Permalink
feat: add all current functions BTT
Browse files Browse the repository at this point in the history
  • Loading branch information
makcandrov committed Jul 28, 2023
1 parent d131ed0 commit f566d0b
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 2 deletions.
180 changes: 178 additions & 2 deletions test/blue_tests.tree
Original file line number Diff line number Diff line change
@@ -1,6 +1,182 @@
.
└── transferOwnership(address newOwner) external onlyOwner/
├── when msg.sender not owner/
│ └── revert with NOT_OWNER
└── when msg.sender is owner/
└── should set owner to newOwner
.
└── enableIrm(IIrm irm) external onlyOwner/
├── when msg.sender not owner/
│ └── revert with NOT_OWNER
└── when msg.sender is owner/
└── should set isIrmEnabled[irm] to true
.
└── enableLltv(uint256 lltv) external onlyOwner/
├── when msg.sender not owner/
│ └── revert with NOT_OWNER
└── when msg.sender is owner/
├── when lltv >= WAD/
│ └── revert with LLTV_TOO_HIGH
└── when lltv < WAD/
└── should set isLltvEnabled[lltv] to true
.
└── setFee(Market memory market, uint256 newFee) external onlyOwner/
├── when msg.sender not owner/
│ └── revert with NOT_OWNER
└── when msg.sender is owner/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when newFee > MAX_FEE/
│ └── revert with MAX_FEE_EXCEEDED
└── when newFee <= MAX_FEE/
└── should set fee[id] to newFee
.
└── setFeeRecipient(address recipient) external onlyOwner/
├── when msg.sender not owner/
│ └── revert with NOT_OWNER
└── when msg.sender is owner/
└── should set feeRecipient to recipient
.
└── createMarket(Market memory market) external/
├── when irm is not enabled/
│ └── revert with IRM_NOT_ENABLED
└── when irm is enabled/
├── when lltv is not enabled/
│ └── revert with LLTV_NOT_ENABLED
└── when lltv is enabled/
├── when market is already created/
│ └── revert with MARKET_CREATED
└── when market is not already created/
└── it should create market

.
└── supply(Market calldata market, uint256 amount, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when the amount to supply is zero/
└── revert with ZERO_AMOUNT
└── when market is created/
├── when the amount to supply is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to supply is not zero/
├── it should add amount.toSharesDown(totalSupply[id], totalSupplyShares[id]) to supplyShare[id][onBehalf]
├── it should add amount.toSharesDown(totalSupply[id], totalSupplyShares[id]) to totalSupplyShares[id]
├── it should add amount to totalSupply[id]
└── it should make the ERC-20 transfer (checks on blue and supplier balances)
.
└── withdraw(Market memory market, uint256 amount, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when the amount to withdraw is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to withdraw is not zero/
├── when not sender and not approved/
│ └── revert with MANAGER_NOT_APPROVED
└── when sender or approved/
├── when totalBorrow > totalSupply/
│ └── revert with INSUFFICIENT_LIQUIDITY
└── when totalBorrow <= totalSupply/
├── it should remove amount.toSharesUp(totalSupply[id], totalSupplyShares[id]) to supplyShare[id][onBehalf]
├── it should remove amount.toSharesUp(totalSupply[id], totalSupplyShares[id]) to totalSupplyShares[id]
├── it should remouve amount from totalSupply[id]
└── it should make the ERC-20 transfer (checks on blue and withdrawer balances)
.
└── borrow(Market memory market, uint256 amount, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when the amount to borrow is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to borrow is not zero/
├── when not sender and not approved/
│ └── revert with MANAGER_NOT_APPROVED
└── when sender or approved/
├── when position not healthy/
│ └── revert with INSUFFICIENT_COLLATERAL
└── when position healthy/
├── when totalBorrow > totalSupply/
│ └── revert with INSUFFICIENT_LIQUIDITY
└── when totalBorrow <= totalSupply/
├── it should add amount.toSharesUp(totalBorrow[id], totalBorrowShares[id]) to borrowShare[id][onBehalf]
├── it should add amount.toSharesUp(totalBorrow[id], totalBorrowShares[id]) to totalBorrowShares[id]
├── it should add amount to totalBorrow[id]
└── it should make the ERC-20 transfer (checks on blue and borrower balances)
.
└── repay(Market memory market, uint256 amount, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when the amount to repay is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to repay is not zero/
├── it should remove amount.toSharesDown(totalBorrow[id], totalBorrowShares[id]) from borrowShare[id][onBehalf]
├── it should remove amount.toSharesDown(totalBorrow[id], totalBorrowShares[id]) from totalBorrowShares[id],
├── it should remove amount from totalBorrow[id]
└── it should make the ERC-20 transfer (checks on blue and repayer balances)
.
└── supplyCollateral(Market memory market, uint256 amount, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when the amount to supply is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to supply is not zero/
├── it should add amount to collateral[id][onBehalf]
└── it should make the ERC-20 transfer (checks on blue and supplier balances)
.
└── withdrawCollateral(Market memory market, uint256 amount, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when the amount to withdraw is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to withdraw is not zero/
├── when not sender and not approved/
│ └── revert with MANAGER_NOT_APPROVED
└── when sender or approved/
├── when position not healthy/
│ └── revert with INSUFFICIENT_COLLATERAL
└── when position healthy/
├── it should remove amount from collateral[id][onBehalf]
└── it should make the ERC-20 transfer (checks on blue and withdrawer balances)
.
└── liquidate(Market memory market, address borrower, address onBehalf) external/
├── when market is not created/
│ └── revert with MARKET_NOT_CREATED
└── when market is created/
├── when the amount to seized is zero/
│ └── revert with ZERO_AMOUNT
└── when the amount to seized is not zero/
├── when position is healthy/
│ └── revert with HEALTHY_POSITION
└── when the position not healthy/
├── it should compute repaid = seized.mulWadUp(collateralPrice).divWadUp(incentive).divWadUp(borrowablePrice);
├── it should remove repaid.toSharesDown(totalBorrow[id], totalBorrowShares[id]) from borrowShare[id][borrower]
├── it should remove repaid.toSharesDown(totalBorrow[id], totalBorrowShares[id]) from totalBorrowShares[id]
├── it should remove repaid from totalBorrow[id]
├── it should remove seized from collateral[id][borrower]
├── it should make the ERC-20 transfers (checks on blue and liquidator balances)
└── if after the liquidation the borrower's collateral is 0/
└── it should realise bad debt/
├── it should compute badDebt = borrowShare[id][borrower].toAssetsUp(totalBorrow[id], totalBorrowShares[id])
├── it should remove bad debt from totalSupply[id]
├── it should remove bad debt from totalBorrow[id]
├── it should remove borrowShare[id][borrower] from totalBorrowShares[id]
└── it should set borrowShare[id][borrower] to 0
.
└── setApproval(address manager, bool isAllowed) external/
└── should set isApproved[msg.sender][manager] to isAllowed
.
└── _accrueInterests(Market memory market, Id id) internal/
├── when marketTotalBorrow is 0/
│ └── it should just set lastUpdate to block.timestamp
└── when marketTotalBorrow is not 0/
├── when lastUpdate = block.timestamp/
│ └── it should just set lastUpdate to block.timestamp
└── when lastUpdate doesn't equal block.timestamp/
├── it should add accruedInterests to totalBorrow
├── it should add accruedInterests to totalSupply
└── when fee[id] != 0/
├── it should add accruedInterests.mulWadDown(fee[id]) to feeAmount
├── it should add feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount) to supplyShare[id][feeRecipient]
└── it should add feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount) to totalSupplyShares[id]
96 changes: 96 additions & 0 deletions test/forge/BlueBase.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.20;

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 private constant BORROWER = address(1234);
address private constant LIQUIDATOR = address(5678);
uint256 private constant LLTV = 0.8 ether;
address private constant OWNER = address(0xdead);

Blue private blue;
ERC20 private borrowableAsset;
ERC20 private collateralAsset;
Oracle private borrowableOracle;
Oracle private collateralOracle;
Irm private 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(
IERC20(address(borrowableAsset)),
IERC20(address(collateralAsset)),
borrowableOracle,
collateralOracle,
irm,
LLTV
);
id = Id.wrap(keccak256(abi.encode(market)));

vm.startPrank(OWNER);
blue.enableIrm(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.supplyShare(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.borrowShare(id, user);
if (borrowerShares == 0) return 0;

uint256 totalShares = blue.totalBorrowShares(id);
uint256 totalBorrow = blue.totalBorrow(id);
return borrowerShares.divWadUp(totalShares).mulWadUp(totalBorrow);
}
}
22 changes: 22 additions & 0 deletions test/forge/integration/TestIntegrationSupply.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.20;

import "test/forge/BlueBase.t.sol";

contract BlueBaseTest is BlueBaseTest {
function testSupplyUnknownMarket(Market memory marketFuzz) public {
vm.assume(neq(marketFuzz, market));

vm.expectRevert("unknown market");
blue.supply(marketFuzz, 1, address(this));
}

function testSupplyUnknownMarket() public {
vm.expectRevert("zero amount");
blue.supply(market, 0, address(this));
}

function testSupply(uint256 amount) {}

function testSupplyOnBehalf(uint256 amount, address onBehalf) {}
}

0 comments on commit f566d0b

Please sign in to comment.