Skip to content

Commit d1e3e01

Browse files
authored
feat: max collateral cap (#132)
* add max collateral cap * disable borrow when utilization rate exceed max * fix testcase failure * add error define
1 parent a76bb9e commit d1e3e01

20 files changed

Lines changed: 422 additions & 89 deletions

abis/LendPool.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,11 @@
859859
"internalType": "uint256",
860860
"name": "maxTokenId",
861861
"type": "uint256"
862+
},
863+
{
864+
"internalType": "uint256",
865+
"name": "maxCollateralCap",
866+
"type": "uint256"
862867
}
863868
],
864869
"internalType": "struct DataTypes.NftData",
@@ -1072,6 +1077,11 @@
10721077
"internalType": "uint8",
10731078
"name": "id",
10741079
"type": "uint8"
1080+
},
1081+
{
1082+
"internalType": "uint256",
1083+
"name": "maxUtilizationRate",
1084+
"type": "uint256"
10751085
}
10761086
],
10771087
"internalType": "struct DataTypes.ReserveData",
@@ -1380,6 +1390,24 @@
13801390
"stateMutability": "nonpayable",
13811391
"type": "function"
13821392
},
1393+
{
1394+
"inputs": [
1395+
{
1396+
"internalType": "address",
1397+
"name": "asset",
1398+
"type": "address"
1399+
},
1400+
{
1401+
"internalType": "uint256",
1402+
"name": "maxCap",
1403+
"type": "uint256"
1404+
}
1405+
],
1406+
"name": "setNftMaxCollateralCap",
1407+
"outputs": [],
1408+
"stateMutability": "nonpayable",
1409+
"type": "function"
1410+
},
13831411
{
13841412
"inputs": [
13851413
{
@@ -1470,6 +1498,24 @@
14701498
"stateMutability": "nonpayable",
14711499
"type": "function"
14721500
},
1501+
{
1502+
"inputs": [
1503+
{
1504+
"internalType": "address",
1505+
"name": "asset",
1506+
"type": "address"
1507+
},
1508+
{
1509+
"internalType": "uint256",
1510+
"name": "maxUtilRate",
1511+
"type": "uint256"
1512+
}
1513+
],
1514+
"name": "setReserveMaxUtilizationRate",
1515+
"outputs": [],
1516+
"stateMutability": "nonpayable",
1517+
"type": "function"
1518+
},
14731519
{
14741520
"inputs": [
14751521
{

abis/LendPoolAddressesProvider.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,19 @@
266266
"name": "WalletBalanceProviderUpdated",
267267
"type": "event"
268268
},
269+
{
270+
"inputs": [],
271+
"name": "RISK_ADMIN",
272+
"outputs": [
273+
{
274+
"internalType": "bytes32",
275+
"name": "",
276+
"type": "bytes32"
277+
}
278+
],
279+
"stateMutability": "view",
280+
"type": "function"
281+
},
269282
{
270283
"inputs": [
271284
{

abis/LendPoolConfigurator.json

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,25 @@
233233
"name": "NftInitialized",
234234
"type": "event"
235235
},
236+
{
237+
"anonymous": false,
238+
"inputs": [
239+
{
240+
"indexed": true,
241+
"internalType": "address",
242+
"name": "asset",
243+
"type": "address"
244+
},
245+
{
246+
"indexed": false,
247+
"internalType": "uint256",
248+
"name": "maxCap",
249+
"type": "uint256"
250+
}
251+
],
252+
"name": "NftMaxCollateralCapChanged",
253+
"type": "event"
254+
},
236255
{
237256
"anonymous": false,
238257
"inputs": [
@@ -436,6 +455,25 @@
436455
"name": "ReserveInterestRateChanged",
437456
"type": "event"
438457
},
458+
{
459+
"anonymous": false,
460+
"inputs": [
461+
{
462+
"indexed": true,
463+
"internalType": "address",
464+
"name": "asset",
465+
"type": "address"
466+
},
467+
{
468+
"indexed": false,
469+
"internalType": "uint256",
470+
"name": "maxUtilRate",
471+
"type": "uint256"
472+
}
473+
],
474+
"name": "ReserveMaxUtilizationRateChanged",
475+
"type": "event"
476+
},
439477
{
440478
"anonymous": false,
441479
"inputs": [
@@ -449,6 +487,19 @@
449487
"name": "ReserveUnfrozen",
450488
"type": "event"
451489
},
490+
{
491+
"inputs": [],
492+
"name": "RISK_ADMIN",
493+
"outputs": [
494+
{
495+
"internalType": "bytes32",
496+
"name": "",
497+
"type": "bytes32"
498+
}
499+
],
500+
"stateMutability": "view",
501+
"type": "function"
502+
},
452503
{
453504
"inputs": [
454505
{
@@ -543,9 +594,14 @@
543594
"internalType": "uint256",
544595
"name": "maxTokenId",
545596
"type": "uint256"
597+
},
598+
{
599+
"internalType": "uint256",
600+
"name": "maxCollateralCap",
601+
"type": "uint256"
546602
}
547603
],
548-
"internalType": "struct ILendPoolConfigurator.ConfigNftInput[]",
604+
"internalType": "struct ConfigTypes.ConfigNftInput[]",
549605
"name": "inputs",
550606
"type": "tuple[]"
551607
}
@@ -568,9 +624,14 @@
568624
"internalType": "uint256",
569625
"name": "reserveFactor",
570626
"type": "uint256"
627+
},
628+
{
629+
"internalType": "uint256",
630+
"name": "maxUtilizationRate",
631+
"type": "uint256"
571632
}
572633
],
573-
"internalType": "struct ILendPoolConfigurator.ConfigReserveInput[]",
634+
"internalType": "struct ConfigTypes.ConfigReserveInput[]",
574635
"name": "inputs",
575636
"type": "tuple[]"
576637
}
@@ -920,6 +981,24 @@
920981
"stateMutability": "nonpayable",
921982
"type": "function"
922983
},
984+
{
985+
"inputs": [
986+
{
987+
"internalType": "address[]",
988+
"name": "assets",
989+
"type": "address[]"
990+
},
991+
{
992+
"internalType": "uint256",
993+
"name": "maxCap",
994+
"type": "uint256"
995+
}
996+
],
997+
"name": "setNftMaxCollateralCap",
998+
"outputs": [],
999+
"stateMutability": "nonpayable",
1000+
"type": "function"
1001+
},
9231002
{
9241003
"inputs": [
9251004
{
@@ -1046,6 +1125,24 @@
10461125
"stateMutability": "nonpayable",
10471126
"type": "function"
10481127
},
1128+
{
1129+
"inputs": [
1130+
{
1131+
"internalType": "address[]",
1132+
"name": "assets",
1133+
"type": "address[]"
1134+
},
1135+
{
1136+
"internalType": "uint256",
1137+
"name": "maxUtilRate",
1138+
"type": "uint256"
1139+
}
1140+
],
1141+
"name": "setReserveMaxUtilizationRate",
1142+
"outputs": [],
1143+
"stateMutability": "nonpayable",
1144+
"type": "function"
1145+
},
10491146
{
10501147
"inputs": [
10511148
{

contracts/interfaces/ILendPool.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@ interface ILendPool {
464464

465465
function setReserveConfiguration(address asset, uint256 configuration) external;
466466

467+
function setReserveMaxUtilizationRate(address asset, uint256 maxUtilRate) external;
468+
467469
function setNftConfiguration(address asset, uint256 configuration) external;
468470

469471
function setNftMaxSupplyAndTokenId(
@@ -472,6 +474,8 @@ interface ILendPool {
472474
uint256 maxTokenId
473475
) external;
474476

477+
function setNftMaxCollateralCap(address asset, uint256 maxCap) external;
478+
475479
function setMaxNumberOfReserves(uint256 val) external;
476480

477481
function setMaxNumberOfNfts(uint256 val) external;

contracts/interfaces/ILendPoolConfigurator.sol

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,6 @@
22
pragma solidity 0.8.4;
33

44
interface ILendPoolConfigurator {
5-
struct ConfigReserveInput {
6-
address asset;
7-
uint256 reserveFactor;
8-
}
9-
10-
struct ConfigNftInput {
11-
address asset;
12-
uint256 baseLTV;
13-
uint256 liquidationThreshold;
14-
uint256 liquidationBonus;
15-
uint256 redeemDuration;
16-
uint256 auctionDuration;
17-
uint256 redeemFine;
18-
uint256 redeemThreshold;
19-
uint256 minBidFine;
20-
uint256 maxSupply;
21-
uint256 maxTokenId;
22-
}
23-
245
/**
256
* @dev Emitted when a reserve is initialized.
267
* @param asset The address of the underlying asset of the reserve
@@ -92,6 +73,8 @@ interface ILendPoolConfigurator {
9273
**/
9374
event ReserveInterestRateChanged(address indexed asset, address strategy);
9475

76+
event ReserveMaxUtilizationRateChanged(address indexed asset, uint256 maxUtilRate);
77+
9578
/**
9679
* @dev Emitted when a nft is initialized.
9780
* @param asset The address of the underlying asset of the nft
@@ -152,6 +135,8 @@ interface ILendPoolConfigurator {
152135

153136
event NftMaxSupplyAndTokenIdChanged(address indexed asset, uint256 maxSupply, uint256 maxTokenId);
154137

138+
event NftMaxCollateralCapChanged(address indexed asset, uint256 maxCap);
139+
155140
event LoanRepaidInterceptorApproval(address indexed interceptor, bool approved);
156141

157142
event FlashLoanLockerApproval(address indexed locker, bool approved);

contracts/libraries/helpers/Errors.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ library Errors {
5050
string public constant VL_SPECIFIED_RESERVE_NOT_BORROWED_BY_USER = "318";
5151
string public constant VL_HEALTH_FACTOR_HIGHER_THAN_LIQUIDATION_THRESHOLD = "319";
5252
string public constant VL_PRICE_STALE = "320";
53+
string public constant VL_EXCEED_MAX_UTILIZATION_RATE = "321";
5354

5455
//lend pool errors
5556
string public constant LP_CALLER_NOT_LEND_POOL_CONFIGURATOR = "400"; // 'The caller of the function is not the lending pool configurator'
@@ -73,6 +74,7 @@ library Errors {
7374
string public constant LP_NFT_SUPPLY_NUM_EXCEED_MAX_LIMIT = "418";
7475
string public constant LP_CALLER_NOT_VALID_INTERCEPTOR = "419";
7576
string public constant LP_CALLER_NOT_VALID_LOCKER = "420";
77+
string public constant LP_NFT_COLLATERAL_NUM_EXCEED_CAP_LIMIT = "421";
7678

7779
//lend pool loan errors
7880
string public constant LPL_INVALID_LOAN_STATE = "480";

contracts/libraries/logic/BorrowLogic.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ library BorrowLogic {
8888
address nftOracle;
8989
address loanAddress;
9090
uint256 totalSupply;
91+
uint256 bnftTotalSupply;
9192
}
9293

9394
/**
@@ -183,6 +184,9 @@ library BorrowLogic {
183184
);
184185

185186
if (vars.loanId == 0) {
187+
vars.bnftTotalSupply = IERC721EnumerableUpgradeable(nftData.bNftAddress).totalSupply();
188+
require(vars.bnftTotalSupply < nftData.maxCollateralCap, Errors.LP_NFT_COLLATERAL_NUM_EXCEED_CAP_LIMIT);
189+
186190
IERC721Upgradeable(params.nftAsset).safeTransferFrom(vars.initiator, address(this), params.nftTokenId);
187191

188192
vars.loanId = ILendPoolLoan(vars.loanAddress).createLoan(

0 commit comments

Comments
 (0)