Skip to content

Commit 2d950be

Browse files
committed
add fee rate limit for liquidation cet
1 parent e931b3c commit 2d950be

File tree

8 files changed

+225
-103
lines changed

8 files changed

+225
-103
lines changed

api/side/lending/params.pulsar.go

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

proto/side/lending/params.proto

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ option go_package = "github.com/sideprotocol/side/x/lending/types";
1010
message Params {
1111
// final timeout duration for loan
1212
google.protobuf.Duration final_timeout_duration = 1 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true];
13+
// maximum fee rate multiplier for liquidation cet; 0 means no limit
14+
int64 max_liquidation_fee_rate_multiplier = 2;
1315
// request fee collector address
14-
string request_fee_collector = 2;
16+
string request_fee_collector = 3;
1517
// origination fee collector address
16-
string origination_fee_collector = 3;
18+
string origination_fee_collector = 4;
1719
// protocol fee collector address
18-
string protocol_fee_collector = 4;
20+
string protocol_fee_collector = 5;
1921
}

x/lending/keeper/dlc.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (k Keeper) GetDLCMeta(ctx sdk.Context, loanId string) *types.DLCMeta {
3636
}
3737

3838
// UpdateDLCMeta updates the dlc meta of the given loan with the given params
39-
func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt.Packet, liquidationCet string, liquidationAdaptorSignatures []string, defaultLiquidationAdaptorSignatures []string, repaymentCet string, repaymentSignatures []string) error {
39+
func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt.Packet, liquidationCet string, liquidationAdaptorSignatures []string, defaultLiquidationAdaptorSignatures []string, repaymentCet string, repaymentSignatures []string, feeRate int64) error {
4040
loan := k.GetLoan(ctx, loanId)
4141
dlcMeta := k.GetDLCMeta(ctx, loanId)
4242

@@ -99,16 +99,9 @@ func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt
9999
return err
100100
}
101101

102-
// get fee rate
103-
// ignore fee rate validity period check and set to default fee rate if it is 0
104-
feeRate := k.btcbridgeKeeper.GetFeeRate(ctx)
105-
if feeRate.Value == 0 {
106-
feeRate.Value = types.DefaultFeeRate
107-
}
108-
109102
// timeout refund transaction can be generated offchain as needed
110103
// err ignored
111-
timeoutRefundTx, _ := types.CreateTimeoutRefundTransaction(depositTxs, vaultPkScript, borrowerPkScript, internalKey, dlcMeta.TimeoutRefundScript, loan.FinalTimeout, feeRate.Value)
104+
timeoutRefundTx, _ := types.CreateTimeoutRefundTransaction(depositTxs, vaultPkScript, borrowerPkScript, internalKey, dlcMeta.TimeoutRefundScript, loan.FinalTimeout, feeRate)
112105

113106
// update dlc meta
114107
dlcMeta.LiquidationCet = types.LiquidationCet{

x/lending/keeper/msg_server_loan.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,19 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
198198
dlcEvent := m.dlcKeeper.GetEvent(ctx, loan.DlcEventId)
199199
m.UpdateDLCEventLiquidatedOutcome(ctx, loan, dlcEvent, liquidationPrice)
200200

201+
// get fee rate
202+
feeRate := m.btcbridgeKeeper.GetFeeRate(ctx)
203+
if err := m.btcbridgeKeeper.CheckFeeRate(ctx, feeRate); err != nil {
204+
return nil, err
205+
}
206+
201207
// verify cets
202-
if err := types.VerifyCets(m.GetDLCMeta(ctx, msg.LoanId), depositTxs, vaultPkScript, loan.BorrowerPubKey, loan.BorrowerAuthPubKey, loan.DCM, dlcEvent, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures); err != nil {
208+
if err := types.VerifyCets(m.GetDLCMeta(ctx, msg.LoanId), depositTxs, vaultPkScript, loan.BorrowerPubKey, loan.BorrowerAuthPubKey, loan.DCM, dlcEvent, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures, feeRate.Value, m.MaxLiquidationFeeRateMultiplier(ctx)); err != nil {
203209
return nil, err
204210
}
205211

206212
// update dlc meta
207-
if err := m.UpdateDLCMeta(ctx, msg.LoanId, depositTxs, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures); err != nil {
213+
if err := m.UpdateDLCMeta(ctx, msg.LoanId, depositTxs, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures, feeRate.Value); err != nil {
208214
return nil, err
209215
}
210216

x/lending/keeper/params.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ func (k Keeper) FinalTimeoutDuration(ctx sdk.Context) int64 {
1111
return int64(k.GetParams(ctx).FinalTimeoutDuration / time.Second)
1212
}
1313

14+
// MaxLiquidationFeeRateMultiplier gets the max fee rate multiplier for liquidation cet
15+
func (k Keeper) MaxLiquidationFeeRateMultiplier(ctx sdk.Context) int64 {
16+
return k.GetParams(ctx).MaxLiquidationFeeRateMultiplier
17+
}
18+
1419
// RequestFeeCollector gets the request fee collector
1520
func (k Keeper) RequestFeeCollector(ctx sdk.Context) string {
1621
return k.GetParams(ctx).RequestFeeCollector

x/lending/types/dlc.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ const (
2626

2727
// liquidation cet sequence
2828
LiquidationCetSequence = wire.MaxTxInSequenceNum
29-
30-
// default fee rate
31-
DefaultFeeRate = 1
3229
)
3330

3431
const (
@@ -79,7 +76,7 @@ func BuildDLCMeta(borrowerPubKey string, borrowerAuthPubKey string, dcmPubKey st
7976
}
8077

8178
// VerifyCets verifies the given cets
82-
func VerifyCets(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScript []byte, borrowerPubKey string, borrowerAuthPubKey string, dcmPubKey string, dlcEvent *dlctypes.DLCEvent, liquidationCet string, liquidationAdaptorSignatures []string, defaultLiquidationAdaptorSignatures []string, repaymentCet string, repaymentSignatures []string) error {
79+
func VerifyCets(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScript []byte, borrowerPubKey string, borrowerAuthPubKey string, dcmPubKey string, dlcEvent *dlctypes.DLCEvent, liquidationCet string, liquidationAdaptorSignatures []string, defaultLiquidationAdaptorSignatures []string, repaymentCet string, repaymentSignatures []string, currentFeeRate int64, maxLiquidationFeeRateMultiplier int64) error {
8380
liquidationAdaptorPoint, err := dlctypes.GetSignaturePointFromEvent(dlcEvent, LiquidatedOutcomeIndex)
8481
if err != nil {
8582
return err
@@ -90,11 +87,11 @@ func VerifyCets(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScript []byt
9087
return err
9188
}
9289

93-
if err := VerifyLiquidationCet(dlcMeta, depositTxs, vaultPkScript, borrowerAuthPubKey, dcmPubKey, liquidationCet, liquidationAdaptorSignatures, liquidationAdaptorPoint); err != nil {
90+
if err := VerifyLiquidationCet(dlcMeta, depositTxs, vaultPkScript, borrowerAuthPubKey, dcmPubKey, liquidationCet, liquidationAdaptorSignatures, liquidationAdaptorPoint, currentFeeRate, maxLiquidationFeeRateMultiplier); err != nil {
9491
return errorsmod.Wrapf(ErrInvalidCET, "invalid liquidation cet: %v", err)
9592
}
9693

97-
if err := VerifyLiquidationCet(dlcMeta, depositTxs, vaultPkScript, borrowerAuthPubKey, dcmPubKey, liquidationCet, defaultLiquidationAdaptorSignatures, defaultLiquidationAdaptorPoint); err != nil {
94+
if err := VerifyLiquidationCet(dlcMeta, depositTxs, vaultPkScript, borrowerAuthPubKey, dcmPubKey, liquidationCet, defaultLiquidationAdaptorSignatures, defaultLiquidationAdaptorPoint, currentFeeRate, maxLiquidationFeeRateMultiplier); err != nil {
9895
return errorsmod.Wrapf(ErrInvalidCET, "invalid default liquidation cet: %v", err)
9996
}
10097

@@ -106,7 +103,7 @@ func VerifyCets(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScript []byt
106103
}
107104

108105
// VerifyLiquidationCet verifies the given liquidation cet and corresponding adaptor signatures
109-
func VerifyLiquidationCet(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScript []byte, borrowerAuthPubKey string, dcmPubKey string, liquidationCET string, adaptorSignatures []string, adaptorPoint []byte) error {
106+
func VerifyLiquidationCet(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScript []byte, borrowerAuthPubKey string, dcmPubKey string, liquidationCET string, adaptorSignatures []string, adaptorPoint []byte, currentFeeRate int64, maxFeeRateMultiplier int64) error {
110107
p, err := psbt.NewFromRawBytes(bytes.NewReader([]byte(liquidationCET)), true)
111108
if err != nil {
112109
return errorsmod.Wrap(ErrInvalidCET, "failed to deserialize cet")
@@ -132,13 +129,8 @@ func VerifyLiquidationCet(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkSc
132129

133130
witnessSize := getCetWitnessSize(CetType_LIQUIDATION, script, controlBlock)
134131

135-
fee, err := p.GetTxFee()
136-
if err != nil {
137-
return errorsmod.Wrapf(ErrInvalidCET, "failed to get tx fee: %v", err)
138-
}
139-
140-
if int64(fee) < GetTxVirtualSize(p.UnsignedTx, witnessSize) {
141-
return errorsmod.Wrap(ErrInvalidCET, "too low fee rate")
132+
if err := checkCetFeeRate(p, witnessSize, currentFeeRate, maxFeeRateMultiplier); err != nil {
133+
return err
142134
}
143135

144136
if err := CheckTransactionWeight(p.UnsignedTx, witnessSize); err != nil {
@@ -230,13 +222,8 @@ func VerifyRepaymentCet(dlcMeta *DLCMeta, depositTxs []*psbt.Packet, vaultPkScri
230222

231223
witnessSize := getCetWitnessSize(CetType_REPAYMENT, script, controlBlock)
232224

233-
fee, err := p.GetTxFee()
234-
if err != nil {
235-
return errorsmod.Wrapf(ErrInvalidCET, "failed to get tx fee: %v", err)
236-
}
237-
238-
if int64(fee) < GetTxVirtualSize(p.UnsignedTx, witnessSize) {
239-
return errorsmod.Wrap(ErrInvalidCET, "too low fee rate")
225+
if err := checkCetFeeRate(p, witnessSize, 0, 0); err != nil {
226+
return err
240227
}
241228

242229
if err := CheckTransactionWeight(p.UnsignedTx, witnessSize); err != nil {
@@ -580,6 +567,26 @@ func getVaultUtxosFromDepositTx(depositTx *psbt.Packet, vaultPkScript []byte) ([
580567
return utxos, nil
581568
}
582569

570+
// checkCetFeeRate checks the fee rate of the given cet
571+
func checkCetFeeRate(p *psbt.Packet, witnessSize int, currentFeeRate int64, maxFeeRateMultiplier int64) error {
572+
virtualSize := GetTxVirtualSize(p.UnsignedTx, witnessSize)
573+
574+
fee, err := p.GetTxFee()
575+
if err != nil {
576+
return errorsmod.Wrapf(ErrInvalidCET, "failed to get tx fee: %v", err)
577+
}
578+
579+
if int64(fee) < virtualSize {
580+
return errorsmod.Wrap(ErrInvalidCET, "too low fee rate")
581+
}
582+
583+
if maxFeeRateMultiplier > 0 && int64(fee) > virtualSize*currentFeeRate*maxFeeRateMultiplier {
584+
return errorsmod.Wrap(ErrInvalidCET, "too high fee rate")
585+
}
586+
587+
return nil
588+
}
589+
583590
// getCetWitnessSize gets the cet witness size according to the given params
584591
// NOTE: The final signature is 64 bytes due to that the sig hash type is SigHashDefault currently.
585592
func getCetWitnessSize(cetType CetType, script []byte, controlBlock []byte) int {

x/lending/types/params.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@ import (
1111

1212
var (
1313
DefaultFinalTimeoutDuration = 30 * 24 * time.Hour // 30 days
14+
15+
// default max fee rate multiplier for liquidation cet
16+
DefaultMaxLiquidationFeeRateMultiplier = int64(5)
1417
)
1518

1619
// DefaultParams returns a default set of parameters
1720
func DefaultParams() Params {
1821
return Params{
19-
FinalTimeoutDuration: DefaultFinalTimeoutDuration,
20-
RequestFeeCollector: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
21-
OriginationFeeCollector: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
22-
ProtocolFeeCollector: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
22+
FinalTimeoutDuration: DefaultFinalTimeoutDuration,
23+
MaxLiquidationFeeRateMultiplier: DefaultMaxLiquidationFeeRateMultiplier,
24+
RequestFeeCollector: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
25+
OriginationFeeCollector: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
26+
ProtocolFeeCollector: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
2327
}
2428
}
2529

@@ -29,6 +33,10 @@ func (p Params) Validate() error {
2933
return errorsmod.Wrap(ErrInvalidParams, "final timeout duration must be greater than 0")
3034
}
3135

36+
if p.MaxLiquidationFeeRateMultiplier < 0 {
37+
return errorsmod.Wrap(ErrInvalidParams, "max liquidation fee rate multiplier cannot be negative")
38+
}
39+
3240
if _, err := sdk.AccAddressFromBech32(p.RequestFeeCollector); err != nil {
3341
return errorsmod.Wrapf(ErrInvalidParams, "invalid request fee collector: %v", err)
3442
}

0 commit comments

Comments
 (0)