From 0fa0454d5eaf22f7e94ba2efa16c7eef37204b9d Mon Sep 17 00:00:00 2001 From: Jeroen Offerijns Date: Fri, 11 Apr 2025 13:40:53 +0200 Subject: [PATCH 1/4] Add min subordination manager --- src/managers/MinSubordinationRatio.sol | 90 ++++++++++++++++++++++++++ src/misc/types/D18.sol | 5 ++ 2 files changed, 95 insertions(+) create mode 100644 src/managers/MinSubordinationRatio.sol diff --git a/src/managers/MinSubordinationRatio.sol b/src/managers/MinSubordinationRatio.sol new file mode 100644 index 000000000..9b4fe70cb --- /dev/null +++ b/src/managers/MinSubordinationRatio.sol @@ -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, divD8} from "src/misc/types/D18.sol"; +import {IERC7726} from "src/misc/interfaces/IERC7726.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 shareClassManager; + + PoolId public immutable poolId; + ShareClassId public immutable seniorScId; + ShareClassId public immutable juniorScId; + + D18 public minJuniorRatio; + + constructor( + IHub hub_, + IHoldings holdings_, + IShareClassManager shareClassManager_, + PoolId poolId_, + ShareClassId seniorScId_, + ShareClassId juniorScId_ + ) Auth(msg.sender) { + hub = hub_; + holdings = holdings_; + shareClassManager = shareClassManager_; + + 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 { + IERC7726 valuation = holdings.valuation(poolId, seniorScId, assetId); + + hub.updatePricePoolPerShare(poolId, seniorScId, seniorNavPerShare, bytes("")); + hub.updatePricePoolPerShare(poolId, juniorScId, juniorNavPerShare, bytes("")); + + hub.approveDeposits(poolId, seniorScId, assetId, seniorDeposit, valuation); + hub.issueShares(poolId, seniorScId, assetId, seniorNavPerShare); + + hub.approveRedeems(poolId, seniorScId, assetId, seniorRedeem); + hub.revokeShares(poolId, seniorScId, assetId, seniorNavPerShare, valuation); + + hub.approveDeposits(poolId, juniorScId, assetId, juniorDeposit, valuation); + hub.issueShares(poolId, juniorScId, assetId, juniorNavPerShare); + + hub.approveRedeems(poolId, juniorScId, assetId, juniorRedeem); + hub.revokeShares(poolId, juniorScId, assetId, juniorNavPerShare, valuation); + + _checkRatio(); + } + + // --- Validation --- + function _checkRatio() internal view { + (uint128 seniorIssuance,) = shareClassManager.shareClassPrice(poolId, seniorScId); + (uint128 juniorIssuance,) = shareClassManager.shareClassPrice(poolId, juniorScId); + + D18 juniorRatio = d18(juniorIssuance) / (d18(seniorIssuance) + d18(juniorIssuance)); + require(juniorRatio >= minJuniorRatio, InvalidJuniorRatio(juniorRatio, minJuniorRatio)); + } +} diff --git a/src/misc/types/D18.sol b/src/misc/types/D18.sol index 3f2112080..7f328bade 100644 --- a/src/misc/types/D18.sol +++ b/src/misc/types/D18.sol @@ -96,6 +96,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 raw(D18 d) pure returns (uint128) { return D18.unwrap(d); } @@ -106,6 +110,7 @@ using { divD8 as /, inner, eq, + geq as >=, mulD8 as *, mulUint128, mulUint256, From 6e42fcb044fe1b9cd7dc7be3bb1981096a56748b Mon Sep 17 00:00:00 2001 From: Jeroen Offerijns Date: Mon, 14 Apr 2025 16:15:50 +0200 Subject: [PATCH 2/4] Use value --- src/managers/MinSubordinationRatio.sol | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/managers/MinSubordinationRatio.sol b/src/managers/MinSubordinationRatio.sol index 9b4fe70cb..2c9381a5d 100644 --- a/src/managers/MinSubordinationRatio.sol +++ b/src/managers/MinSubordinationRatio.sol @@ -81,10 +81,13 @@ contract MinSubordination is Auth { // --- Validation --- function _checkRatio() internal view { - (uint128 seniorIssuance,) = shareClassManager.shareClassPrice(poolId, seniorScId); - (uint128 juniorIssuance,) = shareClassManager.shareClassPrice(poolId, juniorScId); + (uint128 seniorIssuance, D18 seniorPrice) = shareClassManager.shareClassPrice(poolId, seniorScId); + (uint128 juniorIssuance, D18 juniorPrice) = shareClassManager.shareClassPrice(poolId, juniorScId); - D18 juniorRatio = d18(juniorIssuance) / (d18(seniorIssuance) + d18(juniorIssuance)); + D18 seniorValue = d18(seniorIssuance) * seniorPrice; + D18 juniorValue = d18(juniorIssuance) * juniorPrice; + + D18 juniorRatio = juniorValue / (seniorValue + juniorValue); require(juniorRatio >= minJuniorRatio, InvalidJuniorRatio(juniorRatio, minJuniorRatio)); } } From 3533df4440aaf61e5050f3eac433c2d04e4716be Mon Sep 17 00:00:00 2001 From: Jeroen Offerijns Date: Wed, 28 May 2025 08:40:51 +0200 Subject: [PATCH 3/4] Update for latest Hub interface --- src/managers/MinSubordinationRatio.sol | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/managers/MinSubordinationRatio.sol b/src/managers/MinSubordinationRatio.sol index 2c9381a5d..98c9e8281 100644 --- a/src/managers/MinSubordinationRatio.sol +++ b/src/managers/MinSubordinationRatio.sol @@ -2,9 +2,9 @@ pragma solidity 0.8.28; import {Auth} from "src/misc/Auth.sol"; -import {D18, d18, divD8} from "src/misc/types/D18.sol"; -import {IERC7726} from "src/misc/interfaces/IERC7726.sol"; +import {D18, d18} from "src/misc/types/D18.sol"; +import {IValuation} from "src/common/interfaces/IValuation.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"; @@ -18,7 +18,7 @@ contract MinSubordination is Auth { IHub public immutable hub; IHoldings public immutable holdings; - IShareClassManager public immutable shareClassManager; + IShareClassManager public immutable scm; PoolId public immutable poolId; ShareClassId public immutable seniorScId; @@ -29,14 +29,14 @@ contract MinSubordination is Auth { constructor( IHub hub_, IHoldings holdings_, - IShareClassManager shareClassManager_, + IShareClassManager scm_, PoolId poolId_, ShareClassId seniorScId_, ShareClassId juniorScId_ ) Auth(msg.sender) { hub = hub_; holdings = holdings_; - shareClassManager = shareClassManager_; + scm = scm_; poolId = poolId_; seniorScId = seniorScId_; @@ -59,30 +59,30 @@ contract MinSubordination is Auth { uint128 juniorRedeem, D18 juniorNavPerShare ) external auth { - IERC7726 valuation = holdings.valuation(poolId, seniorScId, assetId); + IValuation valuation = holdings.valuation(poolId, seniorScId, assetId); - hub.updatePricePoolPerShare(poolId, seniorScId, seniorNavPerShare, bytes("")); - hub.updatePricePoolPerShare(poolId, juniorScId, juniorNavPerShare, bytes("")); + hub.updateSharePrice(poolId, seniorScId, seniorNavPerShare); + hub.updateSharePrice(poolId, juniorScId, juniorNavPerShare); - hub.approveDeposits(poolId, seniorScId, assetId, seniorDeposit, valuation); - hub.issueShares(poolId, seniorScId, assetId, seniorNavPerShare); + hub.approveDeposits(poolId, seniorScId, assetId, scm.nowDepositEpoch(seniorScId, assetId), seniorDeposit); + hub.issueShares(poolId, seniorScId, assetId, scm.nowIssueEpoch(seniorScId, assetId), seniorNavPerShare); - hub.approveRedeems(poolId, seniorScId, assetId, seniorRedeem); - hub.revokeShares(poolId, seniorScId, assetId, seniorNavPerShare, valuation); + hub.approveRedeems(poolId, seniorScId, assetId, scm.nowRedeemEpoch(seniorScId, assetId), seniorRedeem); + hub.revokeShares(poolId, seniorScId, assetId, scm.nowRevokeEpoch(seniorScId, assetId), seniorNavPerShare); - hub.approveDeposits(poolId, juniorScId, assetId, juniorDeposit, valuation); - hub.issueShares(poolId, juniorScId, assetId, juniorNavPerShare); + hub.approveDeposits(poolId, juniorScId, assetId, scm.nowDepositEpoch(juniorScId, assetId), juniorDeposit); + hub.issueShares(poolId, juniorScId, assetId, scm.nowIssueEpoch(juniorScId, assetId), juniorNavPerShare); - hub.approveRedeems(poolId, juniorScId, assetId, juniorRedeem); - hub.revokeShares(poolId, juniorScId, assetId, juniorNavPerShare, valuation); + hub.approveRedeems(poolId, juniorScId, assetId, scm.nowRedeemEpoch(juniorScId, assetId), juniorRedeem); + hub.revokeShares(poolId, juniorScId, assetId, scm.nowRevokeEpoch(juniorScId, assetId), juniorNavPerShare); _checkRatio(); } // --- Validation --- function _checkRatio() internal view { - (uint128 seniorIssuance, D18 seniorPrice) = shareClassManager.shareClassPrice(poolId, seniorScId); - (uint128 juniorIssuance, D18 juniorPrice) = shareClassManager.shareClassPrice(poolId, juniorScId); + (uint128 seniorIssuance, D18 seniorPrice) = scm.metrics(seniorScId); + (uint128 juniorIssuance, D18 juniorPrice) = scm.metrics(juniorScId); D18 seniorValue = d18(seniorIssuance) * seniorPrice; D18 juniorValue = d18(juniorIssuance) * juniorPrice; From cd5a510d4c75da86b2e51bdfdc82cc8faf0be9bb Mon Sep 17 00:00:00 2001 From: Jeroen Offerijns Date: Wed, 28 May 2025 09:10:12 +0200 Subject: [PATCH 4/4] Fix warning --- src/managers/MinSubordinationRatio.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/managers/MinSubordinationRatio.sol b/src/managers/MinSubordinationRatio.sol index 98c9e8281..95b551983 100644 --- a/src/managers/MinSubordinationRatio.sol +++ b/src/managers/MinSubordinationRatio.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.28; import {Auth} from "src/misc/Auth.sol"; import {D18, d18} from "src/misc/types/D18.sol"; -import {IValuation} from "src/common/interfaces/IValuation.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"; @@ -59,8 +58,6 @@ contract MinSubordination is Auth { uint128 juniorRedeem, D18 juniorNavPerShare ) external auth { - IValuation valuation = holdings.valuation(poolId, seniorScId, assetId); - hub.updateSharePrice(poolId, seniorScId, seniorNavPerShare); hub.updateSharePrice(poolId, juniorScId, juniorNavPerShare);