Skip to content

Commit 60f9ccb

Browse files
authored
feat: Add liquidatable flag to collateral reserve in Spoke (#1042)
1 parent ba544f0 commit 60f9ccb

23 files changed

+261
-354
lines changed

snapshots/Spoke.Operations.ZeroRiskPremium.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"borrow: first": "191060",
33
"borrow: second action, same reserve": "171032",
4-
"liquidationCall (receiveShares): full": "299685",
5-
"liquidationCall (receiveShares): partial": "299403",
6-
"liquidationCall: full": "309785",
7-
"liquidationCall: partial": "309503",
4+
"liquidationCall (receiveShares): full": "299717",
5+
"liquidationCall (receiveShares): partial": "299435",
6+
"liquidationCall: full": "309817",
7+
"liquidationCall: partial": "309535",
88
"permitReserve + repay (multicall)": "165645",
99
"permitReserve + supply (multicall)": "146478",
1010
"permitReserve + supply + enable collateral (multicall)": "160189",

snapshots/Spoke.Operations.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"borrow: first": "261456",
33
"borrow: second action, same reserve": "204428",
4-
"liquidationCall (receiveShares): full": "333248",
5-
"liquidationCall (receiveShares): partial": "332966",
6-
"liquidationCall: full": "343348",
7-
"liquidationCall: partial": "343066",
4+
"liquidationCall (receiveShares): full": "333280",
5+
"liquidationCall (receiveShares): partial": "332998",
6+
"liquidationCall: full": "343380",
7+
"liquidationCall: partial": "343098",
88
"permitReserve + repay (multicall)": "162966",
99
"permitReserve + supply (multicall)": "146478",
1010
"permitReserve + supply + enable collateral (multicall)": "160189",

src/spoke/Spoke.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ abstract contract Spoke is ISpoke, Multicall, NoncesKeyed, AccessManagedUpgradea
154154
initPaused: config.paused,
155155
initFrozen: config.frozen,
156156
initBorrowable: config.borrowable,
157+
initLiquidatable: config.liquidatable,
157158
initReceiveSharesEnabled: config.receiveSharesEnabled
158159
})
159160
});
@@ -179,6 +180,7 @@ abstract contract Spoke is ISpoke, Multicall, NoncesKeyed, AccessManagedUpgradea
179180
initPaused: config.paused,
180181
initFrozen: config.frozen,
181182
initBorrowable: config.borrowable,
183+
initLiquidatable: config.liquidatable,
182184
initReceiveSharesEnabled: config.receiveSharesEnabled
183185
});
184186
emit UpdateReserveConfig(reserveId, config);
@@ -550,6 +552,7 @@ abstract contract Spoke is ISpoke, Multicall, NoncesKeyed, AccessManagedUpgradea
550552
paused: reserve.flags.paused(),
551553
frozen: reserve.flags.frozen(),
552554
borrowable: reserve.flags.borrowable(),
555+
liquidatable: reserve.flags.liquidatable(),
553556
receiveSharesEnabled: reserve.flags.receiveSharesEnabled()
554557
});
555558
}

src/spoke/SpokeConfigurator.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ contract SpokeConfigurator is Ownable2Step, ISpokeConfigurator {
116116
targetSpoke.updateReserveConfig(reserveId, reserveConfig);
117117
}
118118

119+
/// @inheritdoc ISpokeConfigurator
120+
function updateLiquidatable(
121+
address spoke,
122+
uint256 reserveId,
123+
bool liquidatable
124+
) external onlyOwner {
125+
ISpoke targetSpoke = ISpoke(spoke);
126+
ISpoke.ReserveConfig memory reserveConfig = targetSpoke.getReserveConfig(reserveId);
127+
reserveConfig.liquidatable = liquidatable;
128+
targetSpoke.updateReserveConfig(reserveId, reserveConfig);
129+
}
130+
119131
/// @inheritdoc ISpokeConfigurator
120132
function updateReceiveSharesEnabled(
121133
address spoke,

src/spoke/interfaces/ISpoke.sol

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ interface ISpoke is ISpokeBase, IMulticall, INoncesKeyed, IAccessManaged {
3838
/// @dev paused True if all actions are prevented for the reserve.
3939
/// @dev frozen True if new activity is prevented for the reserve.
4040
/// @dev borrowable True if the reserve is borrowable.
41+
/// @dev liquidatable True if the reserve can be liquidated when used as collateral.
4142
/// @dev receiveSharesEnabled True if the liquidator can receive collateral shares during liquidation.
4243
struct ReserveConfig {
4344
uint24 collateralRisk;
4445
bool paused;
4546
bool frozen;
4647
bool borrowable;
48+
bool liquidatable;
4749
bool receiveSharesEnabled;
4850
}
4951

@@ -244,11 +246,14 @@ interface ISpoke is ISpokeBase, IMulticall, INoncesKeyed, IAccessManaged {
244246
/// @dev Can only occur during an attempted `supply`, `borrow`, or `setUsingAsCollateral` action.
245247
error ReserveFrozen();
246248

249+
/// @notice Thrown when the collateral reserve is not enabled to be liquidated.
250+
error CollateralCannotBeLiquidated();
251+
247252
/// @notice Thrown when an action causes a user's health factor to fall below the liquidation threshold.
248253
error HealthFactorBelowThreshold();
249254

250-
/// @notice Thrown when collateral cannot be liquidated.
251-
error CollateralCannotBeLiquidated();
255+
/// @notice Thrown when reserve is not enabled as collateral during liquidation.
256+
error ReserveNotEnabledAsCollateral();
252257

253258
/// @notice Thrown when a specified reserve is not supplied by the user during liquidation.
254259
error ReserveNotSupplied();

src/spoke/interfaces/ISpokeConfigurator.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ interface ISpokeConfigurator {
9191
/// @param borrowable The new borrowable flag.
9292
function updateBorrowable(address spoke, uint256 reserveId, bool borrowable) external;
9393

94+
/// @notice Updates the liquidatable flag of a reserve.
95+
/// @param spoke The address of the spoke.
96+
/// @param reserveId The identifier of the reserve.
97+
/// @param liquidatable The new liquidatable flag.
98+
function updateLiquidatable(address spoke, uint256 reserveId, bool liquidatable) external;
99+
94100
/// @notice Updates whether receiving shares on liquidation is enabled.
95101
/// @param spoke The address of the spoke.
96102
/// @param reserveId The identifier of the reserve.

src/spoke/libraries/LiquidationLogic.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,14 @@ library LiquidationLogic {
359359
);
360360
require(params.collateralReserveBalance > 0, ISpoke.ReserveNotSupplied());
361361
require(params.debtReserveBalance > 0, ISpoke.ReserveNotBorrowed());
362+
require(params.collateralReserveFlags.liquidatable(), ISpoke.CollateralCannotBeLiquidated());
362363
require(
363364
params.healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
364365
ISpoke.HealthFactorNotBelowThreshold()
365366
);
366367
require(
367368
params.collateralFactor > 0 && params.isUsingAsCollateral,
368-
ISpoke.CollateralCannotBeLiquidated()
369+
ISpoke.ReserveNotEnabledAsCollateral()
369370
);
370371
if (params.receiveShares) {
371372
require(

src/spoke/libraries/ReserveFlagsMap.sol

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,30 @@ library ReserveFlagsMap {
1414
uint8 internal constant FROZEN_MASK = 0x02;
1515
/// @dev Mask for the `borrowable` flag.
1616
uint8 internal constant BORROWABLE_MASK = 0x04;
17+
/// @dev Mask for the `liquidatable` flag.
18+
uint8 internal constant LIQUIDATABLE_MASK = 0x08;
1719
/// @dev Mask for the `receiveSharesEnabled` flag.
18-
uint8 internal constant RECEIVE_SHARES_ENABLED_MASK = 0x08;
20+
uint8 internal constant RECEIVE_SHARES_ENABLED_MASK = 0x10;
1921

2022
/// @notice Initializes the ReserveFlags with the given values.
2123
/// @param initPaused The initial `paused` flag status.
2224
/// @param initFrozen The initial `frozen` flag status.
2325
/// @param initBorrowable The initial `borrowable` flag status.
26+
/// @param initLiquidatable The initial `liquidatable` flag status.
2427
/// @param initReceiveSharesEnabled The initial `receiveSharesEnabled` flag status.
2528
/// @return The initialized ReserveFlags.
2629
function create(
2730
bool initPaused,
2831
bool initFrozen,
2932
bool initBorrowable,
33+
bool initLiquidatable,
3034
bool initReceiveSharesEnabled
3135
) internal pure returns (ReserveFlags) {
3236
uint8 flags = 0;
3337
flags = _setStatus(flags, PAUSED_MASK, initPaused);
3438
flags = _setStatus(flags, FROZEN_MASK, initFrozen);
3539
flags = _setStatus(flags, BORROWABLE_MASK, initBorrowable);
40+
flags = _setStatus(flags, LIQUIDATABLE_MASK, initLiquidatable);
3641
flags = _setStatus(flags, RECEIVE_SHARES_ENABLED_MASK, initReceiveSharesEnabled);
3742
return ReserveFlags.wrap(flags);
3843
}
@@ -61,6 +66,14 @@ library ReserveFlagsMap {
6166
return ReserveFlags.wrap(_setStatus(ReserveFlags.unwrap(flags), BORROWABLE_MASK, status));
6267
}
6368

69+
/// @notice Sets the new status for the `liquidatable` flag.
70+
/// @param flags The current ReserveFlags.
71+
/// @param status The new status for the `liquidatable` flag.
72+
/// @return The updated ReserveFlags.
73+
function setLiquidatable(ReserveFlags flags, bool status) internal pure returns (ReserveFlags) {
74+
return ReserveFlags.wrap(_setStatus(ReserveFlags.unwrap(flags), LIQUIDATABLE_MASK, status));
75+
}
76+
6477
/// @notice Sets the new status for the `receiveSharesEnabled` flag.
6578
/// @param flags The current ReserveFlags.
6679
/// @param status The new status for the `receiveSharesEnabled` flag.
@@ -96,6 +109,13 @@ library ReserveFlagsMap {
96109
return (ReserveFlags.unwrap(flags) & BORROWABLE_MASK) != 0;
97110
}
98111

112+
/// @notice Returns the `liquidatable` flag status.
113+
/// @param flags The current ReserveFlags.
114+
/// @return True if the flag is set.
115+
function liquidatable(ReserveFlags flags) internal pure returns (bool) {
116+
return (ReserveFlags.unwrap(flags) & LIQUIDATABLE_MASK) != 0;
117+
}
118+
99119
/// @notice Returns the `receiveSharesEnabled` flag status.
100120
/// @param flags The current ReserveFlags.
101121
/// @return True if the flag is set.

0 commit comments

Comments
 (0)