Skip to content
Merged
41 changes: 28 additions & 13 deletions src/periphery/blue-fallback-rolling/BlueFallbackRolling.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,46 +27,61 @@ contract BlueFallbackRolling is IBlueFallbackRolling {
BLUE = _blue;
}

/// @param start The start time of the rolling period.
/// @param incentive The caller incentive as a WAD-scaled percentage of the debt rolled.
/// @dev The LLTV of the Blue market must be greater than or equal to the LLTV of the Midnight market.
function setConfig(bytes32 midnightId, bytes32 blueId, uint64 start, uint64 incentive, bool enabled)
external
override
{
require(incentive <= WAD, IncentiveTooHigh());
function setConfig(
bytes32 midnightId,
bytes32 blueId,
uint64 start,
uint64 end,
uint64 incentiveAtStart,
uint64 incentiveAtEnd,
bool enabled
) external override {
require(start < end, EndNotAfterStart());
require(incentiveAtStart <= WAD, IncentiveTooHigh());
require(incentiveAtEnd <= WAD, IncentiveTooHigh());
Comment thread
peyha marked this conversation as resolved.

isConfig[msg.sender][keccak256(abi.encode(midnightId, blueId, start, incentive))] = enabled;
isConfig[msg.sender][keccak256(abi.encode(midnightId, blueId, start, end, incentiveAtStart, incentiveAtEnd))] =
enabled;

emit SetConfig(msg.sender, midnightId, blueId, start, incentive, enabled);
emit SetConfig(msg.sender, midnightId, blueId, start, end, incentiveAtStart, incentiveAtEnd, enabled);
}

function roll(
Market memory midnightMarket,
MarketParams memory blueMarketParams,
address user,
uint64 start,
uint64 incentive,
uint64 end,
uint64 incentiveAtStart,
uint64 incentiveAtEnd,
uint256 assets
) external override {
bytes32 midnightId = IdLib.toId(midnightMarket);
bytes32 blueId = Id.unwrap(blueMarketParams.id());
require(isConfig[user][keccak256(abi.encode(midnightId, blueId, start, incentive))], NotConfigured());
require(
isConfig[user][keccak256(abi.encode(midnightId, blueId, start, end, incentiveAtStart, incentiveAtEnd))],
NotConfigured()
);
require(blueMarketParams.loanToken == midnightMarket.loanToken, InconsistentLoanToken());
require(block.timestamp >= start, NotStarted());
require(block.timestamp <= end, Ended());
uint128 collateralBitmap = IMidnight(MIDNIGHT).collateralBitmap(midnightId, user);
require(UtilsLib.countBits(collateralBitmap) == 1, IncorrectActivatedCollateral());
uint256 collateralIndex = UtilsLib.msb(collateralBitmap);
require(
blueMarketParams.collateralToken == midnightMarket.collateralParams[collateralIndex].token,
InconsistentCollateralToken()
);
require(midnightMarket.collateralParams[collateralIndex].lltv <= blueMarketParams.lltv, BlueLltvTooLow());
Comment on lines 72 to +76

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these checks (as well as the loan token check) are not perfect because the users could set non-valid configs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potential solution, check these in setConfig and use a midnight and blue market instead of their respective ids (it would be more expensive in calldata though)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not too bad that one can set an invalid config, but IMO we should do either all checks in setConfig (meaning you can't enable an invalid config) or all checks in roll

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imho it's better to do all check in setConfig to prevent a user from setting something invalid by accident, feeling safe, and then getting liquidated because rolling was not possible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are currently 4 checks on a given config: start <= end, incentives <= WAD, loan token match and collateral token match. We can't really check the collateral tokens because the config might be set before the user supply any collateral into midnight. It's also more expensive in gas to check the loan token in setConfig because in the current version we only use the market Ids. So I slightly favor the current version

Comment thread
peyha marked this conversation as resolved.

// Round in favor of the Midnight position.
Comment thread
MathisGD marked this conversation as resolved.
uint256 collateralAssets = IMidnight(MIDNIGHT).collateral(midnightId, user, collateralIndex)
.mulDivDown(assets, IMidnight(MIDNIGHT).debt(midnightId, user));
// Round in favor of the borrower.
uint256 incentiveAssets = UtilsLib.mulDivDown(assets, incentive, WAD);
// Round against the roller.
uint256 incentiveFactor = incentiveAtStart
+ UtilsLib.mulDivDown(incentiveAtEnd - incentiveAtStart, block.timestamp - start, end - start);
uint256 incentiveAssets = UtilsLib.mulDivDown(assets, incentiveFactor, WAD);

emit Roll(msg.sender, user, midnightId, blueId, assets, collateralAssets, incentiveAssets);

Expand Down
21 changes: 18 additions & 3 deletions src/periphery/blue-fallback-rolling/IBlueFallbackRolling.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {Market} from "../../interfaces/IMidnight.sol";

interface IBlueFallbackRolling is IMorphoSupplyCollateralCallback {
/// ERRORS ///
error BlueLltvTooLow();
error Ended();
error EndNotAfterStart();
error IncentiveTooHigh();
error IncorrectActivatedCollateral();
error InconsistentCollateralToken();
Expand All @@ -22,7 +25,9 @@ interface IBlueFallbackRolling is IMorphoSupplyCollateralCallback {
bytes32 indexed midnightId,
bytes32 indexed blueId,
uint256 start,
uint256 incentive,
uint256 end,
uint256 incentiveAtStart,
uint256 incentiveAtEnd,
bool enabled
);
event Roll(
Expand All @@ -41,13 +46,23 @@ interface IBlueFallbackRolling is IMorphoSupplyCollateralCallback {
function isConfig(address user, bytes32 configId) external view returns (bool);

/// FUNCTIONS ///
function setConfig(bytes32 midnightId, bytes32 blueId, uint64 start, uint64 incentive, bool enabled) external;
function setConfig(
bytes32 midnightId,
bytes32 blueId,
uint64 start,
uint64 end,
uint64 incentiveAtStart,
uint64 incentiveAtEnd,
bool enabled
) external;
function roll(
Market memory midnightMarket,
MarketParams memory blueMarketParams,
address user,
uint64 start,
uint64 incentive,
uint64 end,
uint64 incentiveAtStart,
uint64 incentiveAtEnd,
uint256 assets
) external;
}
Loading