Skip to content
90 changes: 90 additions & 0 deletions src/managers/MinSubordinationRatio.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {Auth} from "src/misc/Auth.sol";
import {D18, d18} from "src/misc/types/D18.sol";

import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";

import {IHub} from "src/hub/interfaces/IHub.sol";
import {IHoldings} from "src/hub/interfaces/IHoldings.sol";
import {IShareClassManager} from "src/hub/interfaces/IShareClassManager.sol";

contract MinSubordination is Auth {
error InvalidJuniorRatio(D18 newRatio, D18 minRatio);

IHub public immutable hub;
IHoldings public immutable holdings;
IShareClassManager public immutable scm;

PoolId public immutable poolId;
ShareClassId public immutable seniorScId;
ShareClassId public immutable juniorScId;

D18 public minJuniorRatio;

constructor(
IHub hub_,
IHoldings holdings_,
IShareClassManager scm_,
PoolId poolId_,
ShareClassId seniorScId_,
ShareClassId juniorScId_
) Auth(msg.sender) {
hub = hub_;
holdings = holdings_;
scm = scm_;

poolId = poolId_;
seniorScId = seniorScId_;
juniorScId = juniorScId_;
}

// --- Administration ---
function setMinJuniorRatio(D18 newRatio) external auth {
minJuniorRatio = newRatio;
_checkRatio();
}

// --- Pool management ---
function fulfill(
AssetId assetId,
uint128 seniorDeposit,
uint128 seniorRedeem,
D18 seniorNavPerShare,
uint128 juniorDeposit,
uint128 juniorRedeem,
D18 juniorNavPerShare
) external auth {
hub.updateSharePrice(poolId, seniorScId, seniorNavPerShare);
hub.updateSharePrice(poolId, juniorScId, juniorNavPerShare);

hub.approveDeposits(poolId, seniorScId, assetId, scm.nowDepositEpoch(seniorScId, assetId), seniorDeposit);
hub.issueShares(poolId, seniorScId, assetId, scm.nowIssueEpoch(seniorScId, assetId), seniorNavPerShare, 0);

hub.approveRedeems(poolId, seniorScId, assetId, scm.nowRedeemEpoch(seniorScId, assetId), seniorRedeem);
hub.revokeShares(poolId, seniorScId, assetId, scm.nowRevokeEpoch(seniorScId, assetId), seniorNavPerShare, 0);

hub.approveDeposits(poolId, juniorScId, assetId, scm.nowDepositEpoch(juniorScId, assetId), juniorDeposit);
hub.issueShares(poolId, juniorScId, assetId, scm.nowIssueEpoch(juniorScId, assetId), juniorNavPerShare, 0);

hub.approveRedeems(poolId, juniorScId, assetId, scm.nowRedeemEpoch(juniorScId, assetId), juniorRedeem);
hub.revokeShares(poolId, juniorScId, assetId, scm.nowRevokeEpoch(juniorScId, assetId), juniorNavPerShare, 0);

_checkRatio();
}

// --- Validation ---
function _checkRatio() internal view {
(uint128 seniorIssuance, D18 seniorPrice) = scm.metrics(seniorScId);
(uint128 juniorIssuance, D18 juniorPrice) = scm.metrics(juniorScId);

D18 seniorValue = d18(seniorIssuance) * seniorPrice;
D18 juniorValue = d18(juniorIssuance) * juniorPrice;

D18 juniorRatio = juniorValue / (seniorValue + juniorValue);
require(juniorRatio >= minJuniorRatio, InvalidJuniorRatio(juniorRatio, minJuniorRatio));
}
}
5 changes: 5 additions & 0 deletions src/misc/types/D18.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ function eq(D18 a, D18 b) pure returns (bool) {
return D18.unwrap(a) == D18.unwrap(b);
}

function geq(D18 a, D18 b) pure returns (bool) {
return D18.unwrap(a) >= D18.unwrap(b);
}

function isZero(D18 a) pure returns (bool) {
return D18.unwrap(a) == 0;
}
Expand All @@ -108,6 +112,7 @@ using {
sub as -,
divD18 as /,
eq,
geq as >=,
mulD18 as *,
mulUint128,
mulUint256,
Expand Down
Loading