Skip to content

Commit

Permalink
Merge branch 'main' into refactor/create-market
Browse files Browse the repository at this point in the history
  • Loading branch information
makcandrov committed Aug 3, 2023
2 parents 375a77d + 66d0bf3 commit aef4c0c
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 11 deletions.
59 changes: 48 additions & 11 deletions src/Blue.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {IERC20} from "./interfaces/IERC20.sol";
import {IOracle} from "./interfaces/IOracle.sol";
import {Id, Market, Signature, IBlue} from "./interfaces/IBlue.sol";

import {Events} from "./libraries/Events.sol";
import {Errors} from "./libraries/Errors.sol";
import {SharesMath} from "./libraries/SharesMath.sol";
import {FixedPointMathLib} from "./libraries/FixedPointMathLib.sol";
Expand Down Expand Up @@ -91,15 +92,21 @@ contract Blue is IBlue {

function setOwner(address newOwner) external onlyOwner {
owner = newOwner;

emit Events.SetOwner(newOwner);
}

function enableIrm(address irm) external onlyOwner {
isIrmEnabled[irm] = true;

emit Events.EnableIrm(address(irm));
}

function enableLltv(uint256 lltv) external onlyOwner {
require(lltv < FixedPointMathLib.WAD, Errors.LLTV_TOO_HIGH);
isLltvEnabled[lltv] = true;

emit Events.EnableLltv(lltv);
}

/// @notice It is the owner's responsibility to ensure a fee recipient is set before setting a non-zero fee.
Expand All @@ -108,10 +115,14 @@ contract Blue is IBlue {
require(lastUpdate[id] != 0, Errors.MARKET_NOT_CREATED);
require(newFee <= MAX_FEE, Errors.MAX_FEE_EXCEEDED);
fee[id] = newFee;

emit Events.SetFee(id, newFee);
}

function setFeeRecipient(address recipient) external onlyOwner {
feeRecipient = recipient;

emit Events.SetFeeRecipient(recipient);
}

// Markets management.
Expand All @@ -121,8 +132,9 @@ contract Blue is IBlue {
require(isIrmEnabled[market.irm], Errors.IRM_NOT_ENABLED);
require(isLltvEnabled[market.lltv], Errors.LLTV_NOT_ENABLED);
require(lastUpdate[id] == 0, Errors.MARKET_CREATED);

lastUpdate[id] = block.timestamp;

emit Events.CreateMarket(id, market);
}

// Supply management.
Expand All @@ -141,6 +153,8 @@ contract Blue is IBlue {

totalSupply[id] += amount;

emit Events.Supply(id, msg.sender, onBehalf, amount, shares);

if (data.length > 0) IBlueSupplyCallback(msg.sender).onBlueSupply(amount, data);

IERC20(market.borrowableAsset).safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -162,6 +176,8 @@ contract Blue is IBlue {

totalSupply[id] -= amount;

emit Events.Withdraw(id, msg.sender, onBehalf, receiver, amount, shares);

require(totalBorrow[id] <= totalSupply[id], Errors.INSUFFICIENT_LIQUIDITY);

IERC20(market.borrowableAsset).safeTransfer(receiver, amount);
Expand All @@ -185,6 +201,8 @@ contract Blue is IBlue {

totalBorrow[id] += amount;

emit Events.Borrow(id, msg.sender, onBehalf, receiver, amount, shares);

require(_isHealthy(market, id, onBehalf), Errors.INSUFFICIENT_COLLATERAL);
require(totalBorrow[id] <= totalSupply[id], Errors.INSUFFICIENT_LIQUIDITY);

Expand All @@ -205,6 +223,8 @@ contract Blue is IBlue {

totalBorrow[id] -= amount;

emit Events.Repay(id, msg.sender, onBehalf, amount, shares);

if (data.length > 0) IBlueRepayCallback(msg.sender).onBlueRepay(amount, data);

IERC20(market.borrowableAsset).safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -223,9 +243,9 @@ contract Blue is IBlue {

collateral[id][onBehalf] += amount;

if (data.length > 0) {
IBlueSupplyCollateralCallback(msg.sender).onBlueSupplyCollateral(amount, data);
}
emit Events.SupplyCollateral(id, msg.sender, onBehalf, amount);

if (data.length > 0) IBlueSupplyCollateralCallback(msg.sender).onBlueSupplyCollateral(amount, data);

IERC20(market.collateralAsset).safeTransferFrom(msg.sender, address(this), amount);
}
Expand All @@ -242,6 +262,8 @@ contract Blue is IBlue {

collateral[id][onBehalf] -= amount;

emit Events.WithdrawCollateral(id, msg.sender, onBehalf, receiver, amount);

require(_isHealthy(market, id, onBehalf), Errors.INSUFFICIENT_COLLATERAL);

IERC20(market.collateralAsset).safeTransfer(receiver, amount);
Expand Down Expand Up @@ -274,16 +296,20 @@ contract Blue is IBlue {
collateral[id][borrower] -= seized;

// Realize the bad debt if needed.
uint256 badDebtShares;
if (collateral[id][borrower] == 0) {
uint256 badDebt = borrowShares[id][borrower].toAssetsUp(totalBorrow[id], totalBorrowShares[id]);
badDebtShares = borrowShares[id][borrower];
uint256 badDebt = badDebtShares.toAssetsUp(totalBorrow[id], totalBorrowShares[id]);
totalSupply[id] -= badDebt;
totalBorrow[id] -= badDebt;
totalBorrowShares[id] -= borrowShares[id][borrower];
totalBorrowShares[id] -= badDebtShares;
borrowShares[id][borrower] = 0;
}

IERC20(market.collateralAsset).safeTransfer(msg.sender, seized);

emit Events.Liquidate(id, msg.sender, borrower, repaid, repaidShares, seized, badDebtShares);

if (data.length > 0) IBlueLiquidateCallback(msg.sender).onBlueLiquidate(seized, repaid, data);

IERC20(market.borrowableAsset).safeTransferFrom(msg.sender, address(this), repaid);
Expand All @@ -294,6 +320,8 @@ contract Blue is IBlue {
function flashLoan(address token, uint256 amount, bytes calldata data) external {
IERC20(token).safeTransfer(msg.sender, amount);

emit Events.FlashLoan(msg.sender, token, amount);

IBlueFlashLoanCallback(msg.sender).onBlueFlashLoan(token, amount, data);

IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
Expand All @@ -311,19 +339,25 @@ contract Blue is IBlue {
) external {
require(block.timestamp < deadline, Errors.SIGNATURE_EXPIRED);

bytes32 hashStruct = keccak256(
abi.encode(AUTHORIZATION_TYPEHASH, authorizer, authorized, newIsAuthorized, nonce[authorizer]++, deadline)
);
uint256 usedNonce = nonce[authorizer]++;
bytes32 hashStruct =
keccak256(abi.encode(AUTHORIZATION_TYPEHASH, authorizer, authorized, newIsAuthorized, usedNonce, deadline));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hashStruct));
address signatory = ecrecover(digest, signature.v, signature.r, signature.s);

require(signatory != address(0) && authorizer == signatory, Errors.INVALID_SIGNATURE);

isAuthorized[signatory][authorized] = newIsAuthorized;
emit Events.IncrementNonce(msg.sender, authorizer, usedNonce);

isAuthorized[authorizer][authorized] = newIsAuthorized;

emit Events.SetAuthorization(msg.sender, authorizer, authorized, newIsAuthorized);
}

function setAuthorization(address authorized, bool newIsAuthorized) external {
isAuthorized[msg.sender][authorized] = newIsAuthorized;

emit Events.SetAuthorization(msg.sender, msg.sender, authorized, newIsAuthorized);
}

function _isSenderAuthorized(address user) internal view returns (bool) {
Expand All @@ -345,13 +379,16 @@ contract Blue is IBlue {
totalBorrow[id] = marketTotalBorrow + accruedInterests;
totalSupply[id] += accruedInterests;

uint256 feeShares;
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);
feeShares = feeAmount.mulDivDown(totalSupplyShares[id], totalSupply[id] - feeAmount);
supplyShares[id][feeRecipient] += feeShares;
totalSupplyShares[id] += feeShares;
}

emit Events.AccrueInterests(id, borrowRate, accruedInterests, feeShares);
}

lastUpdate[id] = block.timestamp;
Expand Down
63 changes: 63 additions & 0 deletions src/libraries/Events.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {Id, Market} from "src/libraries/MarketLib.sol";

library Events {
event SupplyCollateral(Id indexed id, address indexed caller, address indexed onBehalf, uint256 amount);
event WithdrawCollateral(
Id indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 amount
);

event Supply(Id indexed id, address indexed caller, address indexed onBehalf, uint256 amount, uint256 shares);
event Withdraw(
Id indexed id,
address caller,
address indexed onBehalf,
address indexed receiver,
uint256 amount,
uint256 shares
);

event Borrow(
Id indexed id,
address caller,
address indexed onBehalf,
address indexed receiver,
uint256 amount,
uint256 shares
);
event Repay(Id indexed id, address indexed caller, address indexed onBehalf, uint256 amount, uint256 shares);

event Liquidate(
Id indexed id,
address indexed caller,
address indexed borrower,
uint256 repaid,
uint256 repaidShares,
uint256 seized,
uint256 badDebtShares
);

event FlashLoan(address indexed caller, address indexed token, uint256 amount);

event SetOwner(address indexed newOwner);

event SetFee(Id indexed id, uint256 fee);

event SetFeeRecipient(address indexed feeRecipient);

event CreateMarket(Id indexed id, Market market);

event SetAuthorization(
address indexed caller, address indexed authorizer, address indexed authorized, bool isAuthorized
);

event IncrementNonce(address indexed caller, address indexed signatory, uint256 usedNonce);

event EnableIrm(address indexed irm);

event EnableLltv(uint256 lltv);

event AccrueInterests(Id indexed id, uint256 borrowRate, uint256 accruedInterests, uint256 feeShares);
}

0 comments on commit aef4c0c

Please sign in to comment.