Skip to content

Commit f5a2f2b

Browse files
suefaykeithsue
authored andcommitted
improve lending pool params
1 parent bc03b9f commit f5a2f2b

8 files changed

Lines changed: 1313 additions & 1097 deletions

File tree

api/side/lending/lending.pulsar.go

Lines changed: 892 additions & 777 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/side/lending/lending.proto

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ message AssetMetadata {
2929
message PoolTrancheConfig {
3030
// maturity duration in seconds
3131
int64 maturity = 1;
32-
// borrow apr permille
33-
uint32 borrow_apr = 2 [(gogoproto.customname) = "BorrowAPR"];
32+
// borrow apr
33+
string borrow_apr = 2 [
34+
(gogoproto.customname) = "BorrowAPR",
35+
(cosmos_proto.scalar) = "cosmos.Dec",
36+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
37+
(gogoproto.nullable) = false
38+
];
3439
}
3540

3641
// Pool config
@@ -65,14 +70,30 @@ message PoolConfig {
6570
cosmos.base.v1beta1.Coin request_fee = 8 [
6671
(gogoproto.nullable) = false
6772
];
68-
// origination fee factor permille
69-
uint32 origination_fee_factor = 9;
70-
// reserve factor permille
71-
uint32 reserve_factor = 10;
72-
// maximum ltv percent
73-
uint32 max_ltv = 11;
74-
// liquidation ltv percent
75-
uint32 liquidation_threshold = 12;
73+
// origination fee factor
74+
string origination_fee_factor = 9 [
75+
(cosmos_proto.scalar) = "cosmos.Dec",
76+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
77+
(gogoproto.nullable) = false
78+
];
79+
// reserve factor
80+
string reserve_factor = 10 [
81+
(cosmos_proto.scalar) = "cosmos.Dec",
82+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
83+
(gogoproto.nullable) = false
84+
];
85+
// maximum ltv
86+
string max_ltv = 11 [
87+
(cosmos_proto.scalar) = "cosmos.Dec",
88+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
89+
(gogoproto.nullable) = false
90+
];
91+
// liquidation ltv
92+
string liquidation_threshold = 12 [
93+
(cosmos_proto.scalar) = "cosmos.Dec",
94+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
95+
(gogoproto.nullable) = false
96+
];
7697
// indicates if the pool is paused
7798
bool paused = 13;
7899
}
@@ -281,7 +302,12 @@ message Loan {
281302
(gogoproto.nullable) = false
282303
];
283304
int64 maturity = 14;
284-
uint32 borrow_apr = 15 [(gogoproto.customname) = "BorrowAPR"];
305+
string borrow_apr = 15 [
306+
(gogoproto.customname) = "BorrowAPR",
307+
(cosmos_proto.scalar) = "cosmos.Dec",
308+
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
309+
(gogoproto.nullable) = false
310+
];
285311
string start_borrow_index = 16 [
286312
(cosmos_proto.scalar) = "cosmos.Dec",
287313
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",

x/lending/keeper/msg_server_loan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (m msgServer) Apply(goCtx context.Context, msg *types.MsgApply) (*types.Msg
106106
PoolId: msg.PoolId,
107107
BorrowAmount: msg.BorrowAmount,
108108
RequestFee: poolConfig.RequestFee,
109-
OriginationFee: msg.BorrowAmount.Amount.Mul(sdkmath.NewInt(int64(poolConfig.OriginationFeeFactor))).Quo(types.Permille),
109+
OriginationFee: msg.BorrowAmount.Amount.ToLegacyDec().Mul(poolConfig.OriginationFeeFactor).TruncateInt(),
110110
Maturity: trancheConfig.Maturity,
111111
BorrowAPR: trancheConfig.BorrowAPR,
112112
DlcEventId: dlcEvent.Id,

x/lending/keeper/pool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ func (k Keeper) UpdatePoolTranches(ctx sdk.Context, pool *types.LendingPool) {
155155
for i, tranche := range pool.Tranches {
156156
trancheConfig, _ := types.GetTrancheConfig(pool.Config.Tranches, tranche.Maturity)
157157

158-
borrowRatePerBlock := sdkmath.LegacyNewDec(int64(trancheConfig.BorrowAPR)).Quo(sdkmath.LegacyNewDec(1000)).Quo(sdkmath.LegacyNewDec(int64(blocksPerYear)))
158+
borrowRatePerBlock := trancheConfig.BorrowAPR.Quo(sdkmath.LegacyNewDec(int64(blocksPerYear)))
159159
borrowIndexRatio := sdkmath.LegacyOneDec().Add(borrowRatePerBlock)
160160

161-
reserveDelta := pool.Tranches[i].TotalBorrowed.ToLegacyDec().Mul(borrowRatePerBlock).MulInt(sdkmath.NewInt(int64(pool.Config.ReserveFactor))).QuoInt(sdkmath.NewInt(1000)).TruncateInt()
161+
reserveDelta := pool.Tranches[i].TotalBorrowed.ToLegacyDec().Mul(borrowRatePerBlock).Mul(pool.Config.ReserveFactor).TruncateInt()
162162

163163
pool.Tranches[i].BorrowIndex = pool.Tranches[i].BorrowIndex.Mul(borrowIndexRatio)
164164
pool.Tranches[i].TotalBorrowed = pool.Tranches[i].TotalBorrowed.ToLegacyDec().Mul(borrowIndexRatio).TruncateInt()

x/lending/keeper/repayment.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (k Keeper) CompleteRepayment(ctx sdk.Context, loan *types.Loan) error {
6868
repayment := k.GetRepayment(ctx, loan.VaultAddress)
6969

7070
interest := repayment.Amount.Sub(loan.BorrowAmount)
71-
protocolFee := sdk.NewCoin(interest.Denom, interest.Amount.Mul(sdkmath.NewInt(int64(pool.Config.ReserveFactor))).Quo(types.Permille))
71+
protocolFee := sdk.NewCoin(interest.Denom, interest.Amount.ToLegacyDec().Mul(pool.Config.ReserveFactor).TruncateInt())
7272

7373
referralFee := sdkmath.ZeroInt()
7474
actualProtocolFee := protocolFee

x/lending/types/lending.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,18 @@ func GetInterest(borrowAmount sdkmath.Int, startBorrowIndex sdkmath.LegacyDec, b
5454
}
5555

5656
// GetTotalInterest calculates the total loan interest based on the given params
57-
func GetTotalInterest(borrowAmount sdkmath.Int, maturity int64, borrowAPR uint32, blocksPerYear uint64) sdkmath.Int {
57+
func GetTotalInterest(borrowAmount sdkmath.Int, maturity int64, borrowAPR sdkmath.LegacyDec, blocksPerYear uint64) sdkmath.Int {
5858
totalBlocks := uint64(maturity) * blocksPerYear / uint64(OneYear)
5959

60-
borrowRatePerBlock := sdkmath.LegacyNewDec(int64(borrowAPR)).Quo(sdkmath.LegacyNewDec(1000)).Quo(sdkmath.LegacyNewDec(int64(blocksPerYear)))
60+
borrowRatePerBlock := borrowAPR.Quo(sdkmath.LegacyNewDec(int64(blocksPerYear)))
6161
borrowIndexRatio := sdkmath.LegacyOneDec().Add(borrowRatePerBlock)
6262

6363
return borrowAmount.ToLegacyDec().Mul(borrowIndexRatio.Power(totalBlocks)).TruncateInt().Sub(borrowAmount)
6464
}
6565

6666
// GetProtocolFee calculates the protocol fee based on the given interest and reserve factor
67-
func GetProtocolFee(interest sdkmath.Int, reserveFactor uint32) sdkmath.Int {
68-
return interest.Mul(sdkmath.NewInt(int64(reserveFactor))).Quo(Permille)
67+
func GetProtocolFee(interest sdkmath.Int, reserveFactor sdkmath.LegacyDec) sdkmath.Int {
68+
return interest.ToLegacyDec().Mul(reserveFactor).TruncateInt()
6969
}
7070

7171
// GetLiquidationPrice calculates the liquidation price according to the liquidation LTV
@@ -74,14 +74,14 @@ func GetProtocolFee(interest sdkmath.Int, reserveFactor uint32) sdkmath.Int {
7474
// liquidation price = (borrow amount + interest) / lltv / collateral amount
7575
// 2. collateral is NOT the base price asset:
7676
// liquidation price = collateral amount * lltv / (borrow amount + interest)
77-
func GetLiquidationPrice(collateralAmount sdkmath.Int, collateralAssetDecimals int, borrowAmount sdkmath.Int, borrowAssetDecimals int, maturity int64, borrowAPR uint32, blocksPerYear uint64, lltv uint32, collateralIsBaseAsset bool) sdkmath.LegacyDec {
77+
func GetLiquidationPrice(collateralAmount sdkmath.Int, collateralAssetDecimals int, borrowAmount sdkmath.Int, borrowAssetDecimals int, maturity int64, borrowAPR sdkmath.LegacyDec, blocksPerYear uint64, lltv sdkmath.LegacyDec, collateralIsBaseAsset bool) sdkmath.LegacyDec {
7878
interest := GetTotalInterest(borrowAmount, maturity, borrowAPR, blocksPerYear)
7979

8080
var liquidationPrice sdkmath.LegacyDec
8181
if collateralIsBaseAsset {
82-
liquidationPrice = borrowAmount.Add(interest).Mul(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals)).Mul(Percent).ToLegacyDec().QuoInt(sdkmath.NewInt(int64(lltv))).QuoInt(collateralAmount).QuoInt(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals))
82+
liquidationPrice = borrowAmount.Add(interest).Mul(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals)).ToLegacyDec().Quo(lltv).QuoInt(collateralAmount).QuoInt(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals))
8383
} else {
84-
liquidationPrice = collateralAmount.Mul(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals)).Mul(sdkmath.NewInt(int64(lltv))).ToLegacyDec().QuoInt(Percent).QuoInt(borrowAmount.Add(interest)).QuoInt(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals))
84+
liquidationPrice = collateralAmount.Mul(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals)).ToLegacyDec().Mul(lltv).QuoInt(borrowAmount.Add(interest)).QuoInt(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals))
8585
}
8686

8787
return NormalizePrice(liquidationPrice, collateralIsBaseAsset)
@@ -97,12 +97,12 @@ func ToBeLiquidated(price sdkmath.LegacyDec, liquidationPrice sdkmath.LegacyDec,
9797
}
9898

9999
// CheckLTV returns true if the collateral amount and borrow amount satisfy the max LTV limitation by the given price, false otherwise
100-
func CheckLTV(collateralAmount sdkmath.Int, collateralAssetDecimals int, borrowAmount sdkmath.Int, borrowAssetDecimals int, maxLTV uint32, price sdkmath.LegacyDec, collateralIsBaseAsset bool) bool {
100+
func CheckLTV(collateralAmount sdkmath.Int, collateralAssetDecimals int, borrowAmount sdkmath.Int, borrowAssetDecimals int, maxLTV sdkmath.LegacyDec, price sdkmath.LegacyDec, collateralIsBaseAsset bool) bool {
101101
if collateralIsBaseAsset {
102-
return collateralAmount.Mul(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals)).Mul(sdkmath.NewInt(int64(maxLTV))).ToLegacyDec().Mul(price).QuoInt(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals)).QuoInt(Percent).TruncateInt().GTE(borrowAmount)
102+
return collateralAmount.Mul(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals)).ToLegacyDec().Mul(maxLTV).Mul(price).QuoInt(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals)).TruncateInt().GTE(borrowAmount)
103103
}
104104

105-
return collateralAmount.Mul(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals)).Mul(sdkmath.NewInt(int64(maxLTV))).ToLegacyDec().Quo(price).QuoInt(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals)).QuoInt(Percent).TruncateInt().GTE(borrowAmount)
105+
return collateralAmount.Mul(sdkmath.NewIntWithDecimal(1, borrowAssetDecimals)).ToLegacyDec().Mul(maxLTV).Quo(price).QuoInt(sdkmath.NewIntWithDecimal(1, collateralAssetDecimals)).TruncateInt().GTE(borrowAmount)
106106
}
107107

108108
// GetPricePair gets the price pair from the given pool config
@@ -292,23 +292,23 @@ func ValidatePoolConfig(config PoolConfig) error {
292292
}
293293

294294
if config.SupplyCap.IsNil() || config.SupplyCap.IsNegative() {
295-
return errorsmod.Wrap(ErrInvalidPoolConfig, "supply cap can not be nil or negative")
295+
return errorsmod.Wrap(ErrInvalidPoolConfig, "supply cap cannot be nil or negative")
296296
}
297297

298298
if config.BorrowCap.IsNil() || config.BorrowCap.IsNegative() {
299-
return errorsmod.Wrap(ErrInvalidPoolConfig, "borrow cap can not be nil or negative")
299+
return errorsmod.Wrap(ErrInvalidPoolConfig, "borrow cap cannot be nil or negative")
300300
}
301301

302302
if config.MinBorrowAmount.IsNil() || config.MinBorrowAmount.IsNegative() {
303-
return errorsmod.Wrap(ErrInvalidPoolConfig, "min borrow amount can not be nil or negative")
303+
return errorsmod.Wrap(ErrInvalidPoolConfig, "min borrow amount cannot be nil or negative")
304304
}
305305

306306
if config.MaxBorrowAmount.IsNil() || config.MaxBorrowAmount.IsNegative() {
307-
return errorsmod.Wrap(ErrInvalidPoolConfig, "max borrow amount can not be nil or negative")
307+
return errorsmod.Wrap(ErrInvalidPoolConfig, "max borrow amount cannot be nil or negative")
308308
}
309309

310310
if config.MinBorrowAmount.IsPositive() && config.MaxBorrowAmount.IsPositive() && config.MaxBorrowAmount.LT(config.MinBorrowAmount) {
311-
return errorsmod.Wrap(ErrInvalidPoolConfig, "max borrow amount can not be less than min borrow amount")
311+
return errorsmod.Wrap(ErrInvalidPoolConfig, "max borrow amount cannot be less than min borrow amount")
312312
}
313313

314314
if err := validatePoolTranches(config.Tranches); err != nil {
@@ -319,19 +319,19 @@ func ValidatePoolConfig(config PoolConfig) error {
319319
return errorsmod.Wrap(ErrInvalidPoolConfig, "invalid request fee")
320320
}
321321

322-
if config.OriginationFeeFactor >= 1000 {
322+
if config.OriginationFeeFactor.IsNegative() || config.OriginationFeeFactor.GTE(sdkmath.LegacyOneDec()) {
323323
return errorsmod.Wrap(ErrInvalidPoolConfig, "invalid origination fee factor")
324324
}
325325

326-
if config.ReserveFactor >= 1000 {
326+
if config.ReserveFactor.IsNegative() || config.ReserveFactor.GTE(sdkmath.LegacyOneDec()) {
327327
return errorsmod.Wrap(ErrInvalidPoolConfig, "invalid reserve factor")
328328
}
329329

330-
if config.LiquidationThreshold == 0 || config.LiquidationThreshold >= 100 {
330+
if !config.LiquidationThreshold.IsPositive() || config.LiquidationThreshold.GTE(sdkmath.LegacyOneDec()) {
331331
return errorsmod.Wrap(ErrInvalidPoolConfig, "invalid liquidation threshold")
332332
}
333333

334-
if config.MaxLtv == 0 || config.MaxLtv >= 100 || config.MaxLtv >= config.LiquidationThreshold {
334+
if !config.MaxLtv.IsPositive() || config.MaxLtv.GTE(sdkmath.LegacyOneDec()) || config.MaxLtv.GTE(config.LiquidationThreshold) {
335335
return errorsmod.Wrap(ErrInvalidPoolConfig, "invalid max ltv")
336336
}
337337

@@ -379,16 +379,16 @@ func validateAssetMetadata(metadata AssetMetadata) error {
379379
// validatePoolTrancheConfig validates the given tranche config
380380
func validatePoolTranches(tranches []PoolTrancheConfig) error {
381381
if len(tranches) == 0 {
382-
return errorsmod.Wrap(ErrInvalidPoolConfig, "tranches can not be empty")
382+
return errorsmod.Wrap(ErrInvalidPoolConfig, "tranches cannot be empty")
383383
}
384384

385385
for _, tranche := range tranches {
386386
if tranche.Maturity <= 0 {
387387
return errorsmod.Wrap(ErrInvalidPoolConfig, "maturity must be greater than 0")
388388
}
389389

390-
if tranche.BorrowAPR == 0 || tranche.BorrowAPR >= 1000 {
391-
return errorsmod.Wrap(ErrInvalidPoolConfig, "borrow apr must be between (0, 1000)")
390+
if !tranche.BorrowAPR.IsPositive() || tranche.BorrowAPR.GTE(sdkmath.LegacyOneDec()) {
391+
return errorsmod.Wrap(ErrInvalidPoolConfig, "borrow apr must be between (0, 1)")
392392
}
393393
}
394394

0 commit comments

Comments
 (0)