@@ -54,19 +54,21 @@ pub struct PoolInfo {
54
54
}
55
55
56
56
pub use pallet:: * ;
57
+ pub mod migrations;
57
58
58
59
#[ frame_support:: pallet]
59
60
pub mod pallet {
60
61
use crate :: { BorrowingPosition , LendingPosition , PoolInfo , WeightInfo } ;
61
62
use common:: prelude:: { Balance , FixedWrapper , SwapAmount } ;
62
63
use common:: {
63
64
balance, AssetIdOf , AssetManager , DEXId , LiquiditySourceFilter , PriceVariant ,
64
- CERES_ASSET_ID , DAI ,
65
+ CERES_ASSET_ID , DAI , KUSD ,
65
66
} ;
66
67
use common:: { LiquidityProxyTrait , PriceToolsProvider , APOLLO_ASSET_ID } ;
67
68
use frame_support:: log:: { debug, warn} ;
68
69
use frame_support:: pallet_prelude:: { ValueQuery , * } ;
69
70
use frame_support:: sp_runtime:: traits:: AccountIdConversion ;
71
+ use frame_support:: traits:: StorageVersion ;
70
72
use frame_support:: PalletId ;
71
73
use frame_system:: offchain:: { SendTransactionTypes , SubmitTransaction } ;
72
74
use frame_system:: pallet_prelude:: * ;
@@ -108,8 +110,12 @@ pub mod pallet {
108
110
109
111
pub type AccountIdOf < T > = <T as frame_system:: Config >:: AccountId ;
110
112
113
+ /// The current storage version.
114
+ pub const STORAGE_VERSION : StorageVersion = StorageVersion :: new ( 1 ) ;
115
+
111
116
#[ pallet:: pallet]
112
117
#[ pallet:: generate_store( pub ( super ) trait Store ) ]
118
+ #[ pallet:: storage_version( STORAGE_VERSION ) ]
113
119
#[ pallet:: without_storage_info]
114
120
pub struct Pallet < T > ( PhantomData < T > ) ;
115
121
@@ -139,6 +145,12 @@ pub mod pallet {
139
145
OptionQuery ,
140
146
> ;
141
147
148
+ /// User AccountId -> Collateral Asset -> Total Collateral Amount
149
+ #[ pallet:: storage]
150
+ #[ pallet:: getter( fn user_total_collateral) ]
151
+ pub type UserTotalCollateral < T : Config > =
152
+ StorageDoubleMap < _ , Identity , AccountIdOf < T > , Identity , AssetIdOf < T > , Balance , OptionQuery > ;
153
+
142
154
#[ pallet:: storage]
143
155
#[ pallet:: getter( fn pool_info) ]
144
156
pub type PoolData < T : Config > = StorageMap < _ , Identity , AssetIdOf < T > , PoolInfo , OptionQuery > ;
@@ -193,6 +205,17 @@ pub mod pallet {
193
205
pub type BorrowingRewards < T : Config > =
194
206
StorageValue < _ , Balance , ValueQuery , FixedBorrowingRewards < T > > ;
195
207
208
+ /// Default collateral factor
209
+ #[ pallet:: type_value]
210
+ pub fn DefaultCollateralFactor < T : Config > ( ) -> Balance {
211
+ balance ! ( 0.001 )
212
+ }
213
+
214
+ #[ pallet:: storage]
215
+ #[ pallet:: getter( fn collateral_factor) ]
216
+ pub type CollateralFactor < T : Config > =
217
+ StorageValue < _ , Balance , ValueQuery , DefaultCollateralFactor < T > > ;
218
+
196
219
#[ pallet:: type_value]
197
220
pub fn FixedLendingRewardsPerBlock < T : Config > ( ) -> Balance {
198
221
balance ! ( 0.03805175 )
@@ -236,6 +259,8 @@ pub mod pallet {
236
259
ChangedRewardsAmount ( AccountIdOf < T > , bool , Balance ) ,
237
260
//// ChangedRewardsAmountPerBlock [who, is_lending, amount]
238
261
ChangedRewardsAmountPerBlock ( AccountIdOf < T > , bool , Balance ) ,
262
+ /// Changed Borrowing factor [who, amount]
263
+ ChangedCollateralFactorAmount ( AccountIdOf < T > , Balance ) ,
239
264
/// Liquidated [who, asset_id]
240
265
Liquidated ( AccountIdOf < T > , AssetIdOf < T > ) ,
241
266
/// Pool removed [who, asset_id]
@@ -542,14 +567,39 @@ pub mod pallet {
542
567
. try_into_balance ( )
543
568
. unwrap_or ( 0 ) ;
544
569
570
+ let mut borrow_info =
571
+ <UserBorrowingInfo < T > >:: get ( borrowing_asset, user. clone ( ) ) . unwrap_or_default ( ) ;
572
+
573
+ if collateral_asset == KUSD . into ( ) {
574
+ let factor = <CollateralFactor < T > >:: get ( ) ;
575
+
576
+ // To get total collateral for a user
577
+ let total_existing_collateral =
578
+ <UserTotalCollateral < T > >:: get ( user. clone ( ) , collateral_asset)
579
+ . unwrap_or ( Zero :: zero ( ) ) ;
580
+
581
+ // Calculate the maximum allowed collateral for KUSD
582
+ let max_allowed_collateral = Self :: calculate_max_allowed_collateral (
583
+ user_lending_info
584
+ . lending_amount
585
+ . saturating_add ( total_existing_collateral) ,
586
+ factor,
587
+ ) ?;
588
+
589
+ let new_total_collateral =
590
+ total_existing_collateral. saturating_add ( collateral_amount) ;
591
+
592
+ ensure ! (
593
+ new_total_collateral <= max_allowed_collateral,
594
+ Error :: <T >:: InvalidCollateralAmount
595
+ ) ;
596
+ }
597
+
545
598
ensure ! (
546
599
collateral_amount <= user_lending_info. lending_amount,
547
600
Error :: <T >:: InvalidCollateralAmount
548
601
) ;
549
602
550
- let mut borrow_info =
551
- <UserBorrowingInfo < T > >:: get ( borrowing_asset, user. clone ( ) ) . unwrap_or_default ( ) ;
552
-
553
603
// Add borrowing amount, collateral amount and interest to user if exists, otherwise create new user
554
604
if let Some ( mut user_info) = borrow_info. get_mut ( & collateral_asset) {
555
605
let block_number = <frame_system:: Pallet < T > >:: block_number ( ) ;
@@ -602,6 +652,9 @@ pub mod pallet {
602
652
<PoolData < T > >:: insert ( collateral_asset, collateral_pool_info) ;
603
653
<PoolData < T > >:: insert ( borrowing_asset, borrow_pool_info) ;
604
654
655
+ // Update the total collateral
656
+ Self :: update_total_collateral ( & user, & collateral_asset, collateral_amount) ?;
657
+
605
658
// Transfer borrowing amount to user
606
659
T :: AssetManager :: transfer_from (
607
660
& borrowing_asset,
@@ -873,6 +926,13 @@ pub mod pallet {
873
926
<PoolData < T > >:: insert ( collateral_asset, collateral_pool_info) ;
874
927
<PoolData < T > >:: insert ( borrowing_asset, borrow_pool_info) ;
875
928
929
+ // Update the total collateral
930
+ Self :: decrease_total_collateral (
931
+ & user,
932
+ & collateral_asset,
933
+ user_info. collateral_amount ,
934
+ ) ?;
935
+
876
936
// Transfer borrowing amount and borrowing interest to pallet
877
937
T :: AssetManager :: transfer_from (
878
938
& borrowing_asset,
@@ -1011,7 +1071,7 @@ pub mod pallet {
1011
1071
// Calculate total borrow and total collateral in dollars
1012
1072
let mut total_borrowed: Balance = 0 ;
1013
1073
1014
- // Distributing and calculating total borrwed
1074
+ // Distributing and calculating total borrowed
1015
1075
for ( collateral_asset, user_info) in user_infos. iter ( ) {
1016
1076
// Calculate collateral in dollars
1017
1077
let collateral_asset_price = Self :: get_price ( * collateral_asset) ;
@@ -1067,6 +1127,13 @@ pub mod pallet {
1067
1127
. total_collateral
1068
1128
. saturating_sub ( user_info. collateral_amount ) ;
1069
1129
1130
+ // Update the total collateral
1131
+ Self :: decrease_total_collateral (
1132
+ & user,
1133
+ collateral_asset,
1134
+ user_info. collateral_amount ,
1135
+ ) ?;
1136
+
1070
1137
<PoolData < T > >:: insert ( * collateral_asset, collateral_pool_info) ;
1071
1138
// Add user's borrowed amount tied with this asset to total_borrowed in given asset
1072
1139
total_borrowed += user_info. borrowing_amount ;
@@ -1225,6 +1292,30 @@ pub mod pallet {
1225
1292
let mut borrow_info =
1226
1293
<UserBorrowingInfo < T > >:: get ( borrowing_asset, user. clone ( ) ) . unwrap_or_default ( ) ;
1227
1294
1295
+ if collateral_asset == KUSD . into ( ) {
1296
+ let factor = <CollateralFactor < T > >:: get ( ) ;
1297
+ // To get total collateral for a user
1298
+ let total_existing_collateral =
1299
+ <UserTotalCollateral < T > >:: get ( user. clone ( ) , collateral_asset)
1300
+ . unwrap_or ( Zero :: zero ( ) ) ;
1301
+
1302
+ // Calculate the maximum allowed collateral for KUSD
1303
+ let max_allowed_collateral = Self :: calculate_max_allowed_collateral (
1304
+ user_lending_info
1305
+ . lending_amount
1306
+ . saturating_add ( total_existing_collateral) ,
1307
+ factor,
1308
+ ) ?;
1309
+
1310
+ let new_total_collateral =
1311
+ total_existing_collateral. saturating_add ( collateral_amount) ;
1312
+
1313
+ ensure ! (
1314
+ new_total_collateral <= max_allowed_collateral,
1315
+ Error :: <T >:: InvalidCollateralAmount
1316
+ ) ;
1317
+ }
1318
+
1228
1319
// Add borrowing amount, collateral amount and interest to user if exists, otherwise return error
1229
1320
if let Some ( mut user_info) = borrow_info. get_mut ( & collateral_asset) {
1230
1321
let block_number = <frame_system:: Pallet < T > >:: block_number ( ) ;
@@ -1262,6 +1353,9 @@ pub mod pallet {
1262
1353
. saturating_sub ( collateral_amount) ;
1263
1354
collateral_pool_info. total_collateral += collateral_amount;
1264
1355
1356
+ // Update the total collateral
1357
+ Self :: update_total_collateral ( & user, & collateral_asset, collateral_amount) ?;
1358
+
1265
1359
<PoolData < T > >:: insert ( collateral_asset, collateral_pool_info) ;
1266
1360
1267
1361
Self :: deposit_event ( Event :: CollateralAdded (
@@ -1273,6 +1367,25 @@ pub mod pallet {
1273
1367
1274
1368
Ok ( ( ) . into ( ) )
1275
1369
}
1370
+
1371
+ /// Change rewards amount
1372
+ #[ pallet:: call_index( 12 ) ]
1373
+ #[ pallet:: weight( <T as Config >:: WeightInfo :: change_collateral_factor( ) ) ]
1374
+ pub fn change_collateral_factor (
1375
+ origin : OriginFor < T > ,
1376
+ amount : Balance ,
1377
+ ) -> DispatchResultWithPostInfo {
1378
+ let user = ensure_signed ( origin) ?;
1379
+
1380
+ if user != AuthorityAccount :: < T > :: get ( ) {
1381
+ return Err ( Error :: < T > :: Unauthorized . into ( ) ) ;
1382
+ }
1383
+
1384
+ <CollateralFactor < T > >:: put ( amount) ;
1385
+
1386
+ Self :: deposit_event ( Event :: ChangedCollateralFactorAmount ( user, amount) ) ;
1387
+ Ok ( ( ) . into ( ) )
1388
+ }
1276
1389
}
1277
1390
1278
1391
/// Validate unsigned call to this pallet.
@@ -1475,6 +1588,47 @@ pub mod pallet {
1475
1588
)
1476
1589
}
1477
1590
1591
+ /// Increase total collateral amount for a user and asset
1592
+ fn update_total_collateral (
1593
+ user : & AccountIdOf < T > ,
1594
+ collateral_asset : & AssetIdOf < T > ,
1595
+ amount_to_add : Balance ,
1596
+ ) -> DispatchResult {
1597
+ <UserTotalCollateral < T > >:: mutate ( user, collateral_asset, |current_collateral| {
1598
+ // If no existing collateral, start with the new amount
1599
+ // Otherwise, add the new amount
1600
+ * current_collateral = Some (
1601
+ current_collateral
1602
+ . unwrap_or ( Zero :: zero ( ) )
1603
+ . saturating_add ( amount_to_add) ,
1604
+ )
1605
+ } ) ;
1606
+
1607
+ Ok ( ( ) )
1608
+ }
1609
+
1610
+ /// Decrease total collateral amount for a user and asset
1611
+ fn decrease_total_collateral (
1612
+ user : & AccountIdOf < T > ,
1613
+ collateral_asset : & AssetIdOf < T > ,
1614
+ amount_to_remove : Balance ,
1615
+ ) -> DispatchResult {
1616
+ <UserTotalCollateral < T > >:: mutate ( user, collateral_asset, |current_collateral| {
1617
+ if let Some ( current) = * current_collateral {
1618
+ let new_amount = current. saturating_sub ( amount_to_remove) ;
1619
+
1620
+ // Remove the entry if it reaches zero, otherwise update
1621
+ if new_amount == Zero :: zero ( ) {
1622
+ * current_collateral = None ;
1623
+ } else {
1624
+ * current_collateral = Some ( new_amount) ;
1625
+ }
1626
+ }
1627
+ } ) ;
1628
+
1629
+ Ok ( ( ) )
1630
+ }
1631
+
1478
1632
pub fn distribute_protocol_interest (
1479
1633
asset_id : AssetIdOf < T > ,
1480
1634
amount : Balance ,
@@ -1565,6 +1719,17 @@ pub mod pallet {
1565
1719
Ok ( ( ) . into ( ) )
1566
1720
}
1567
1721
1722
+ fn calculate_max_allowed_collateral (
1723
+ lending_amount : Balance ,
1724
+ factor : Balance ,
1725
+ ) -> Result < Balance , DispatchError > {
1726
+ Ok (
1727
+ ( FixedWrapper :: from ( lending_amount) * FixedWrapper :: from ( factor) )
1728
+ . try_into_balance ( )
1729
+ . unwrap_or ( 0 ) ,
1730
+ )
1731
+ }
1732
+
1568
1733
fn update_interests ( block_number : BlockNumberFor < T > ) -> Weight {
1569
1734
let mut counter: u64 = 0 ;
1570
1735
let pool_index = block_number % T :: BLOCKS_PER_FIFTEEN_MINUTES ;
0 commit comments