@@ -16,9 +16,10 @@ contract LayerCredit is EVCUtil {
1616 IEulerRouterFactory immutable private routerFactory;
1717 StubOracle immutable private stubOracle;
1818
19+ uint256 private constant MAX_COLLATERALS = 3 ;
20+
1921 address public settingAdmin;
20- uint16 public settingMaxCollaterals = 3 ; // Special value of 0 means system sunset (no new bond creation allowed)
21- uint40 public settingMaxTermDuration = 90 days ;
22+ uint40 public settingMaxTermDuration = 90 days ; // Special value of 0 means system sunset (no new bond creation allowed)
2223 uint40 public settingReserveMultiplier = 20e4 ; // 1e4 scale
2324 uint80 public settingSettlementInterestRate = 21964959992727444861 ; // 100% APY
2425
@@ -56,37 +57,38 @@ contract LayerCredit is EVCUtil {
5657 }
5758
5859
59- struct BondStorage {
60- address vault;
61- uint40 bondId;
62- uint16 state; // 0 = active, 1 = soft settlement, 2 = hard settlement, 3 = dead
60+ struct BondState {
61+ uint8 state; // 0 = none, 1 = active, 2 = soft settlement, 3 = hard settlement, 4 = inactive
6362 uint40 termEnd;
6463 uint40 termStart;
6564 address restrictedLender;
6665 address restrictedBorrower;
66+ uint64 earlyRepayPenalty;
6767 uint40 reserveMultiplier; // 1e4 scale
6868 uint80 settlementInterestRate;
6969 }
7070
71- mapping (address vault = > BondStorage) private bondsByVault;
72- mapping (uint256 bondId = > address vault ) private bondsById;
73- uint256 private nextBondId = 1 ;
71+ mapping (address vault = > BondState) private bondsByVault;
7472 EnumerableSet.AddressSet private activeBonds;
73+ EnumerableSet.AddressSet private settlingBonds;
74+ address [] private inactiveBonds;
7575
7676 mapping (address vault = > mapping (address who = > uint256 shares )) reservedShares;
7777
7878
7979 error SystemSunset ();
8080 error InvalidTermDuration ();
8181 error InvalidNumberOfCollaterals ();
82- error InvalidLTVIndex ();
82+ error InvalidAsset ();
83+ error InvalidLTV ();
8384 error VaultNotEVCCompatible ();
85+ error InvalidEarlyRepayPenalty ();
8486
8587 function deployBond (DeployBondParams memory p ) external returns (address ) {
86- require (settingMaxCollaterals != 0 , SystemSunset ());
88+ require (settingMaxTermDuration != 0 , SystemSunset ());
8789 require (p.termDuration <= settingMaxTermDuration, InvalidTermDuration ());
88-
89- require (p.collaterals. length >= 1 && p.collaterals. length <= settingMaxCollaterals, InvalidNumberOfCollaterals ());
90+ require (p.collaterals. length >= 1 && p.collaterals. length <= MAX_COLLATERALS, InvalidNumberOfCollaterals ());
91+ require (p.earlyRepayPenalty <= 1e18 , InvalidEarlyRepayPenalty ());
9092
9193 IEulerRouter router = IEulerRouter (IEulerRouterFactory (routerFactory).deploy (address (this )));
9294
@@ -100,6 +102,8 @@ contract LayerCredit is EVCUtil {
100102 vault.setLiquidationCoolOffTime (1 );
101103
102104 for (uint256 i = 0 ; i < p.collaterals.length ; i++ ) {
105+ require (p.collaterals[i].asset != address (0 ), InvalidAsset ());
106+
103107 IEVault collateralVault;
104108
105109 if (p.collaterals[i].isExternalVault) {
@@ -111,31 +115,30 @@ contract LayerCredit is EVCUtil {
111115
112116 router.govSetResolvedVault (address (vault), true );
113117
118+ uint16 liqLTV = p.collaterals[i].liquidationLTV;
119+ require (liqLTV > 0.1e4 , InvalidLTV ());
120+
114121 router.govSetConfig (collateralVault.asset (), p.unitOfAccount, address (stubOracle));
115- vault.setLTV (address (collateralVault), uint16 (p.collaterals[i].liquidationLTV * 0.98e18 / 1e18 ), p.collaterals[i].liquidationLTV , 0 );
122+ vault.setLTV (address (collateralVault), uint16 (liqLTV * 0.98e18 / 1e18 ), liqLTV , 0 );
116123 router.govSetConfig (collateralVault.asset (), p.unitOfAccount, p.collaterals[i].oracle);
117124 }
118125
119126 router.transferGovernance (address (0 ));
120127 vault.setGovernorAdmin (address (0 ));
121128
122- bondsByVault[address (vault)] = BondStorage ({
123- vault: address (vault),
124- bondId: uint40 (nextBondId),
129+ bondsByVault[address (vault)] = BondState ({
130+ state: 1 ,
125131 termEnd: uint40 (block .timestamp + p.termDuration),
126132 termStart: uint40 (block .timestamp ),
127133 restrictedLender: p.restrictedLender,
128134 restrictedBorrower: p.restrictedBorrower,
135+ earlyRepayPenalty: p.earlyRepayPenalty,
129136 reserveMultiplier: settingReserveMultiplier,
130137 settlementInterestRate: settingSettlementInterestRate
131138 });
132139
133- bondsById[nextBondId] = address (vault);
134-
135140 activeBonds.add (address (vault));
136141
137- nextBondId++ ;
138-
139142 return address (vault);
140143 }
141144
@@ -149,4 +152,28 @@ contract LayerCredit is EVCUtil {
149152
150153 return newEscrow;
151154 }
155+
156+ function getBond (address bond ) external view returns (BondState memory ) {
157+ return bondsByVault[bond];
158+ }
159+
160+ function getActiveBonds (uint256 start , uint256 end ) external view returns (address [] memory ) {
161+ return getSlice (activeBonds, start, end);
162+ }
163+
164+
165+ error SliceOutOfBounds ();
166+
167+ function getSlice (EnumerableSet.AddressSet storage arr , uint256 start , uint256 end ) internal view returns (address [] memory ) {
168+ uint256 length = arr.length ();
169+ if (end == type (uint256 ).max) end = length;
170+ if (end < start || end > length) revert SliceOutOfBounds ();
171+
172+ address [] memory slice = new address [](end - start);
173+ for (uint256 i; i < end - start; ++ i) {
174+ slice[i] = arr.at (start + i);
175+ }
176+
177+ return slice;
178+ }
152179}
0 commit comments