Skip to content

Commit dd8b032

Browse files
committed
add asset metadata to pool config
1 parent 5ed1c82 commit dd8b032

13 files changed

Lines changed: 2368 additions & 1166 deletions

File tree

api/side/lending/lending.pulsar.go

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

api/side/lending/tx.pulsar.go

Lines changed: 194 additions & 269 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: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ enum PoolStatus {
1616
PAUSED = 2;
1717
}
1818

19+
message AssetMetadata {
20+
string denom = 1;
21+
string symbol = 2;
22+
string price_symbol = 3;
23+
int32 decimals = 4;
24+
}
25+
1926
// Pool tranche config
2027
message PoolTrancheConfig {
2128
// maturity duration in seconds
@@ -28,47 +35,51 @@ message PoolTrancheConfig {
2835

2936
// Pool config
3037
message PoolConfig {
38+
// collateral asset metadata
39+
AssetMetadata collateral_asset = 1 [(gogoproto.nullable) = false];
40+
// lending asset metadata
41+
AssetMetadata lending_asset = 2 [(gogoproto.nullable) = false];
3142
// supply cap
32-
string supply_cap = 1 [
43+
string supply_cap = 3 [
3344
(gogoproto.customtype) = "cosmossdk.io/math.Int",
3445
(gogoproto.nullable) = false
3546
];
3647
// borrow cap
37-
string borrow_cap = 2 [
48+
string borrow_cap = 4 [
3849
(gogoproto.customtype) = "cosmossdk.io/math.Int",
3950
(gogoproto.nullable) = false
4051
];
4152
// minimum amount to be borrowed
42-
string min_borrow_amount = 3 [
53+
string min_borrow_amount = 5 [
4354
(gogoproto.customtype) = "cosmossdk.io/math.Int",
4455
(gogoproto.nullable) = false
4556
];
4657
// maximum amount to be borrowed
47-
string max_borrow_amount = 4 [
58+
string max_borrow_amount = 6 [
4859
(gogoproto.customtype) = "cosmossdk.io/math.Int",
4960
(gogoproto.nullable) = false
5061
];
5162
// tranches
52-
repeated PoolTrancheConfig tranches = 5 [(gogoproto.nullable) = false];
63+
repeated PoolTrancheConfig tranches = 7 [(gogoproto.nullable) = false];
5364
// request fee
54-
cosmos.base.v1beta1.Coin request_fee = 6 [
65+
cosmos.base.v1beta1.Coin request_fee = 8 [
5566
(gogoproto.nullable) = false
5667
];
5768
// origination fee
58-
string origination_fee = 7 [
69+
string origination_fee = 9 [
5970
(gogoproto.customtype) = "cosmossdk.io/math.Int",
6071
(gogoproto.nullable) = false
6172
];
6273
// reserve factor permille
63-
uint32 reserve_factor = 8;
74+
uint32 reserve_factor = 10;
6475
// referral fee factor permille
65-
uint32 referral_fee_factor = 9;
76+
uint32 referral_fee_factor = 11;
6677
// maximum ltv percent
67-
uint32 max_ltv = 10;
78+
uint32 max_ltv = 12;
6879
// liquidation ltv percent
69-
uint32 liquidation_threshold = 11;
80+
uint32 liquidation_threshold = 13;
7081
// indicates if the pool is paused
71-
bool paused = 12;
82+
bool paused = 14;
7283
}
7384

7485
// Pool tranche

proto/side/lending/tx.proto

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ message MsgCreatePool {
4040
string authority = 1;
4141
// pool id
4242
string id = 2;
43-
// lending asset
44-
string lending_asset = 3;
4543
// pool config
46-
PoolConfig config = 4 [(gogoproto.nullable) = false];
44+
PoolConfig config = 3 [(gogoproto.nullable) = false];
4745
}
4846

4947
message MsgCreatePoolResponse{}

x/lending/keeper/dlc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func (k Keeper) GetCetInfos(ctx sdk.Context, loanId string, collateralAmount sdk
4040
liquidationEvent = k.dlcKeeper.GetEvent(ctx, loan.LiquidationEventId)
4141
} else if collateralAmount.Amount.IsPositive() {
4242
liquidationPrice := types.GetLiquidationPrice(collateralAmount.Amount, loan.BorrowAmount.Amount, loan.Maturity, loan.BorrowAPR, k.GetBlocksPerYear(ctx), poolConfig.LiquidationThreshold)
43-
liquidationEvent = k.dlcKeeper.GetEventByPrice(ctx, "BTCUSD", liquidationPrice.String())
43+
liquidationEvent = k.dlcKeeper.GetEventByPrice(ctx, types.GetPricePair(poolConfig), liquidationPrice.String())
4444
}
4545

4646
defaultLiquidationEvent := k.dlcKeeper.GetEvent(ctx, loan.DefaultLiquidationEventId)

x/lending/keeper/msg_server_loan.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,15 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
265265
return nil, nil
266266
}
267267

268+
pricePair := types.GetPricePair(poolConfig)
269+
268270
liquidationPrice := types.GetLiquidationPrice(collateralAmount, loan.BorrowAmount.Amount, loan.Maturity, loan.BorrowAPR, m.GetBlocksPerYear(ctx), poolConfig.LiquidationThreshold)
269-
if !m.dlcKeeper.HasEventByPrice(ctx, "BTCUSD", liquidationPrice.String()) {
271+
if !m.dlcKeeper.HasEventByPrice(ctx, pricePair, liquidationPrice.String()) {
270272
errRejected = errorsmod.Wrap(types.ErrInvalidEvent, "liquidation event does not exist")
271273
return nil, nil
272274
}
273275

274-
liquidationEvent := m.dlcKeeper.GetEventByPrice(ctx, "BTCUSD", liquidationPrice.String())
276+
liquidationEvent := m.dlcKeeper.GetEventByPrice(ctx, pricePair, liquidationPrice.String())
275277
if liquidationEvent.HasTriggered {
276278
errRejected = errorsmod.Wrap(types.ErrInvalidEvent, "liquidation event has triggered")
277279
return nil, nil
@@ -283,7 +285,7 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
283285
return nil, err
284286
}
285287

286-
currentPrice, err := m.GetPrice(ctx, "BTCUSD")
288+
currentPrice, err := m.GetPrice(ctx, pricePair)
287289
if err != nil {
288290
return nil, err
289291
}
@@ -396,7 +398,7 @@ func (m msgServer) Approve(goCtx context.Context, msg *types.MsgApprove) (*types
396398

397399
// authorization submitted
398400
if authorizationId == m.GetAuthorizationId(ctx, msg.Vault) {
399-
currentPrice, err := m.GetPrice(ctx, "BTCUSD")
401+
currentPrice, err := m.GetPrice(ctx, types.GetPricePair(m.GetPool(ctx, loan.VaultAddress).Config))
400402
if err != nil {
401403
return nil, err
402404
}

x/lending/keeper/msg_server_pool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (m msgServer) CreatePool(goCtx context.Context, msg *types.MsgCreatePool) (
3333

3434
pool := &types.LendingPool{
3535
Id: msg.Id,
36-
Supply: sdk.NewCoin(msg.LendingAsset, sdkmath.ZeroInt()),
36+
Supply: sdk.NewCoin(msg.Config.LendingAsset.Denom, sdkmath.ZeroInt()),
3737
TotalSTokens: sdk.NewCoin(msg.Id, sdkmath.ZeroInt()),
3838
Tranches: types.NewTranches(msg.Config.Tranches),
3939
Config: msg.Config,

x/lending/keeper/queries.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (k Keeper) LiquidationEvent(goCtx context.Context, req *types.QueryLiquidat
109109

110110
liquidationPrice := types.GetLiquidationPrice(collateralAmount.Amount, borrowedAmount.Amount, trancheConfig.Maturity, trancheConfig.BorrowAPR, k.GetBlocksPerYear(ctx), poolConfig.LiquidationThreshold)
111111

112-
event := k.dlcKeeper.GetEventByPrice(ctx, "BTCUSD", liquidationPrice.String())
112+
event := k.dlcKeeper.GetEventByPrice(ctx, types.GetPricePair(poolConfig), liquidationPrice.String())
113113
if event == nil {
114114
return nil, status.Error(codes.NotFound, "liquidation event does not exist")
115115
}

x/lending/module/abci.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,14 @@ func handleActiveLoans(ctx sdk.Context, k keeper.Keeper) {
4343

4444
var liquidationInterest sdkmath.Int
4545

46-
currentPrice, err := k.GetPrice(ctx, "BTCUSD")
46+
pool := k.GetPool(ctx, loan.PoolId)
47+
pricePair := types.GetPricePair(pool.Config)
48+
49+
currentPrice, err := k.GetPrice(ctx, pricePair)
4750
if err != nil {
48-
k.Logger(ctx).Info("failed to get price", "err", err)
51+
k.Logger(ctx).Info("failed to get price", "pair", pricePair, "err", err)
4952
}
5053

51-
pool := k.GetPool(ctx, loan.PoolId)
52-
5354
dlcMeta := k.GetDLCMeta(ctx, loan.VaultAddress)
5455

5556
// check if the loan has defaulted
@@ -96,20 +97,23 @@ func handleActiveLoans(ctx sdk.Context, k keeper.Keeper) {
9697

9798
// create liquidation if defaulted or liquidated
9899
if loan.Status == types.LoanStatus_Defaulted || loan.Status == types.LoanStatus_Liquidated {
100+
collateralDenom := pool.Config.CollateralAsset.Denom
101+
debtDenom := pool.Config.LendingAsset.Denom
102+
99103
liquidation := k.LiquidationKeeper().CreateLiquidation(ctx, &liquidationtypes.Liquidation{
100104
LoanId: loan.VaultAddress,
101105
Debtor: loan.Borrower,
102106
DCM: loan.DCM,
103-
CollateralAmount: sdk.NewCoin("sat", loan.CollateralAmount),
104-
ActualCollateralAmount: sdk.NewCoin("sat", sdkmath.NewInt(types.GetLiquidationCetOutput(liquidationCet))),
105-
DebtAmount: sdk.NewCoin(pool.Supply.Denom, loan.BorrowAmount.Amount.Add(liquidationInterest)),
107+
CollateralAmount: sdk.NewCoin(collateralDenom, loan.CollateralAmount),
108+
ActualCollateralAmount: sdk.NewCoin(collateralDenom, sdkmath.NewInt(types.GetLiquidationCetOutput(liquidationCet))),
109+
DebtAmount: sdk.NewCoin(debtDenom, loan.BorrowAmount.Amount.Add(liquidationInterest)),
106110
LiquidatedPrice: currentPrice,
107111
LiquidatedTime: ctx.BlockTime(),
108-
LiquidatedCollateralAmount: sdk.NewCoin("sat", sdkmath.ZeroInt()),
109-
LiquidatedDebtAmount: sdk.NewCoin(pool.Supply.Denom, sdkmath.ZeroInt()),
110-
LiquidationBonusAmount: sdk.NewCoin("sat", sdkmath.ZeroInt()),
111-
ProtocolLiquidationFee: sdk.NewCoin("sat", sdkmath.ZeroInt()),
112-
UnliquidatedCollateralAmount: sdk.NewCoin("sat", sdkmath.ZeroInt()),
112+
LiquidatedCollateralAmount: sdk.NewCoin(collateralDenom, sdkmath.ZeroInt()),
113+
LiquidatedDebtAmount: sdk.NewCoin(debtDenom, sdkmath.ZeroInt()),
114+
LiquidationBonusAmount: sdk.NewCoin(collateralDenom, sdkmath.ZeroInt()),
115+
ProtocolLiquidationFee: sdk.NewCoin(collateralDenom, sdkmath.ZeroInt()),
116+
UnliquidatedCollateralAmount: sdk.NewCoin(collateralDenom, sdkmath.ZeroInt()),
113117
LiquidationCet: liquidationCet,
114118
})
115119

x/lending/types/lending.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import (
44
"encoding/hex"
55
fmt "fmt"
66
"strconv"
7+
"strings"
78
"time"
89

910
errorsmod "cosmossdk.io/errors"
1011
sdkmath "cosmossdk.io/math"
1112

13+
sdk "github.com/cosmos/cosmos-sdk/types"
1214
"github.com/sideprotocol/side/crypto/adaptor"
1315
)
1416

@@ -78,6 +80,11 @@ func AdaptorPointFromSecret(secret []byte) string {
7880
return hex.EncodeToString(adaptor.SecretToPubKey(secret))
7981
}
8082

83+
// GetPricePair gets the price pair from the given pool config
84+
func GetPricePair(poolConfig PoolConfig) string {
85+
return fmt.Sprintf("%s%s", strings.ToUpper(poolConfig.CollateralAsset.PriceSymbol), strings.ToUpper(poolConfig.LendingAsset.PriceSymbol))
86+
}
87+
8188
// HasSupplyCap returns true if the supply cap set in the given pool, false otherwise
8289
func HasSupplyCap(pool *LendingPool) bool {
8390
return pool.Config.SupplyCap.IsPositive()
@@ -180,6 +187,14 @@ func NewTranches(trancheConfigs []PoolTrancheConfig) []PoolTranche {
180187

181188
// ValidatePoolConfig validates the given pool config
182189
func ValidatePoolConfig(config PoolConfig) error {
190+
if err := validateAssetMetadata(config.CollateralAsset); err != nil {
191+
return err
192+
}
193+
194+
if err := validateAssetMetadata(config.LendingAsset); err != nil {
195+
return err
196+
}
197+
183198
if config.SupplyCap.IsNil() || config.SupplyCap.IsNegative() {
184199
return errorsmod.Wrap(ErrInvalidPoolConfig, "supply cap can not be nil or negative")
185200
}
@@ -235,6 +250,26 @@ func ValidatePoolConfig(config PoolConfig) error {
235250
return nil
236251
}
237252

253+
func validateAssetMetadata(metadata AssetMetadata) error {
254+
if err := sdk.ValidateDenom(metadata.Denom); err != nil {
255+
return errorsmod.Wrapf(ErrInvalidPoolConfig, "invalid asset denom")
256+
}
257+
258+
if len(metadata.Symbol) == 0 {
259+
return errorsmod.Wrapf(ErrInvalidPoolConfig, "invalid asset symbol")
260+
}
261+
262+
if len(metadata.PriceSymbol) == 0 {
263+
return errorsmod.Wrapf(ErrInvalidPoolConfig, "invalid asset price symbol")
264+
}
265+
266+
if metadata.Decimals < 0 {
267+
return errorsmod.Wrapf(ErrInvalidPoolConfig, "invalid asset decimals")
268+
}
269+
270+
return nil
271+
}
272+
238273
// validatePoolTrancheConfig validates the given tranche config
239274
func validatePoolTranches(tranches []PoolTrancheConfig) error {
240275
if len(tranches) == 0 {

0 commit comments

Comments
 (0)