Skip to content

Commit 0779ebb

Browse files
committed
support multiple deposit txs for loan authorization
1 parent ae1b89e commit 0779ebb

13 files changed

Lines changed: 1815 additions & 923 deletions

File tree

api/side/lending/lending.pulsar.go

Lines changed: 902 additions & 350 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: 270 additions & 210 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: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ enum LoanStatus {
140140
Closed = 8;
141141
}
142142

143+
// Deposits used for CET authorization
144+
message AuthorizationDeposits {
145+
repeated string deposit_txs = 1;
146+
}
147+
143148
message Loan {
144149
string vault_address = 1; // id
145150
string borrower = 2;
@@ -177,7 +182,7 @@ message Loan {
177182
uint64 liquidation_event_id = 18;
178183
uint64 default_liquidation_event_id = 19;
179184
uint64 repayment_event_id = 20;
180-
repeated string deposit_txs = 21;
185+
repeated AuthorizationDeposits authorization_deposits = 21 [(gogoproto.nullable) = false];
181186
string collateral_amount = 22 [
182187
(gogoproto.customtype) = "cosmossdk.io/math.Int",
183188
(gogoproto.nullable) = false

proto/side/lending/tx.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ message MsgSubmitCets {
111111

112112
string borrower = 1;
113113
string loan_id = 2;
114-
string deposit_tx = 3;
114+
repeated string deposit_txs = 3;
115115
string liquidation_cet = 4;
116116
repeated string liquidation_adaptor_signatures = 5;
117117
repeated string default_liquidation_adaptor_signatures = 6;

x/lending/client/cli/tx.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func CmdApply() *cobra.Command {
173173

174174
func CmdSubmitCets() *cobra.Command {
175175
cmd := &cobra.Command{
176-
Use: `submit-cets [loan id] [deposit tx] [liquidation cet] [liquidation adaptor signatures]
176+
Use: `submit-cets [loan id] [deposit txs] [liquidation cet] [liquidation adaptor signatures]
177177
[default liquidation adaptor signatures] [repayment cet] [repayment signatures]`,
178178
Short: "Submit the related cets of the given loan",
179179
Args: cobra.ExactArgs(7),
@@ -186,7 +186,7 @@ func CmdSubmitCets() *cobra.Command {
186186
msg := types.NewMsgSubmitCets(
187187
clientCtx.GetFromAddress().String(),
188188
args[0],
189-
args[1],
189+
strings.Split(args[1], listSeparator),
190190
args[2],
191191
strings.Split(args[3], listSeparator),
192192
strings.Split(args[4], listSeparator),

x/lending/keeper/approval.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
// HandleApproval performs the loan approval
10-
func (k Keeper) HandleApproval(ctx sdk.Context, sender string, depositTxHash string, loan *types.Loan) error {
10+
func (k Keeper) HandleApproval(ctx sdk.Context, sender string, loan *types.Loan) error {
1111
pool := k.GetPool(ctx, loan.PoolId)
1212
if pool.AvailableAmount.LT(loan.BorrowAmount.Amount) {
1313
return types.ErrInsufficientLiquidity
@@ -43,7 +43,6 @@ func (k Keeper) HandleApproval(ctx sdk.Context, sender string, depositTxHash str
4343
sdk.NewAttribute(types.AttributeKeySender, sender),
4444
sdk.NewAttribute(types.AttributeKeyLoanId, loan.VaultAddress),
4545
sdk.NewAttribute(types.AttributeKeyAmount, amount.String()),
46-
sdk.NewAttribute(types.AttributeKeyDepositTxHash, depositTxHash),
4746
),
4847
)
4948

x/lending/keeper/loan.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,23 @@ func (k Keeper) GetDepositLog(ctx sdk.Context, txid string) *types.DepositLog {
146146
return &depositLog
147147
}
148148

149+
// DepositTxsVerified returns true if all deposit txs verified, false otherwise
150+
func (k Keeper) DepositTxsVerified(ctx sdk.Context, txids []string) bool {
151+
store := ctx.KVStore(k.storeKey)
152+
153+
for _, txid := range txids {
154+
var depositLog types.DepositLog
155+
bz := store.Get(types.DepositLogKey(txid))
156+
k.cdc.MustUnmarshal(bz, &depositLog)
157+
158+
if !depositLog.Verified {
159+
return false
160+
}
161+
}
162+
163+
return true
164+
}
165+
149166
// SetRepayment sets the given repayment
150167
func (k Keeper) SetRepayment(ctx sdk.Context, repayment *types.Repayment) {
151168
store := ctx.KVStore(k.storeKey)

x/lending/keeper/msg_server_loan.go

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -167,39 +167,48 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
167167

168168
vaultPkScript, _ := types.GetPkScriptFromAddress(loan.VaultAddress)
169169

170-
fundTx, _ := psbt.NewFromRawBytes(bytes.NewReader([]byte(msg.DepositTx)), true)
171-
depositTxHash := fundTx.UnsignedTx.TxHash().String()
172-
170+
depositTxs := []*psbt.Packet{}
171+
depositTxHashes := []string{}
173172
collateralAmount := sdkmath.ZeroInt()
174-
for _, out := range fundTx.UnsignedTx.TxOut {
175-
if bytes.Equal(out.PkScript, vaultPkScript) {
176-
collateralAmount = collateralAmount.Add(sdkmath.NewInt(out.Value))
173+
174+
for _, depositTx := range msg.DepositTxs {
175+
p, _ := psbt.NewFromRawBytes(bytes.NewReader([]byte(depositTx)), true)
176+
177+
depositTxs = append(depositTxs, p)
178+
depositTxHashes = append(depositTxHashes, p.UnsignedTx.TxHash().String())
179+
180+
for _, out := range p.UnsignedTx.TxOut {
181+
if bytes.Equal(out.PkScript, vaultPkScript) {
182+
collateralAmount = collateralAmount.Add(sdkmath.NewInt(out.Value))
183+
}
177184
}
178185
}
179186

180187
if collateralAmount.IsZero() {
181188
return nil, errorsmod.Wrap(types.ErrInsufficientCollateral, "collateral amount can not be zero")
182189
}
183190

184-
dlcMeta, err := types.BuildDLCMeta(fundTx, vaultPkScript, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures, loan.BorrowerPubKey, loan.DCM, loan.MaturityTime, loan.FinalTimeout)
191+
dlcMeta, err := types.BuildDLCMeta(depositTxs, vaultPkScript, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures, loan.BorrowerPubKey, loan.DCM, loan.MaturityTime, loan.FinalTimeout)
185192
if err != nil {
186193
return nil, err
187194
}
188195

189196
m.SetDLCMeta(ctx, loan.VaultAddress, dlcMeta)
190197

191-
if !m.HasDepositLog(ctx, depositTxHash) {
192-
depositLog := &types.DepositLog{
193-
Txid: depositTxHash,
194-
VaultAddress: loan.VaultAddress,
195-
DepositTx: msg.DepositTx,
196-
}
198+
for i, depositTx := range msg.DepositTxs {
199+
if !m.HasDepositLog(ctx, depositTxHashes[i]) {
200+
depositLog := &types.DepositLog{
201+
Txid: depositTxHashes[i],
202+
VaultAddress: loan.VaultAddress,
203+
DepositTx: depositTx,
204+
}
197205

198-
m.SetDepositLog(ctx, depositLog)
206+
m.SetDepositLog(ctx, depositLog)
207+
}
199208
}
200209

201210
loan.CollateralAmount = collateralAmount
202-
loan.DepositTxs = append(loan.DepositTxs, depositTxHash)
211+
loan.AuthorizationDeposits = append(loan.AuthorizationDeposits, types.AuthorizationDeposits{DepositTxs: depositTxHashes})
203212

204213
var errRejected error
205214

@@ -214,7 +223,6 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
214223
sdk.NewEvent(
215224
types.EventTypeReject,
216225
sdk.NewAttribute(types.AttributeKeyLoanId, msg.LoanId),
217-
sdk.NewAttribute(types.AttributeKeyDepositTxHash, depositTxHash),
218226
),
219227
)
220228
}
@@ -249,7 +257,7 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
249257

250258
defaultLiquidationEvent := m.dlcKeeper.GetEvent(ctx, loan.DefaultLiquidationEventId)
251259

252-
if err := types.VerifyCets(fundTx, loan.BorrowerPubKey, loan.DCM, liquidationEvent, defaultLiquidationEvent, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures); err != nil {
260+
if err := types.VerifyCets(depositTxs, vaultPkScript, loan.BorrowerPubKey, loan.DCM, liquidationEvent, defaultLiquidationEvent, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures); err != nil {
253261
return nil, err
254262
}
255263

@@ -264,9 +272,9 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
264272
return nil, nil
265273
}
266274

267-
// if deposit tx already verified, approve the loan
268-
if m.GetDepositLog(ctx, depositTxHash).Verified {
269-
if err := m.HandleApproval(ctx, msg.Borrower, depositTxHash, loan); err != nil {
275+
// if all deposit txs already verified, approve the loan
276+
if m.DepositTxsVerified(ctx, depositTxHashes) {
277+
if err := m.HandleApproval(ctx, msg.Borrower, loan); err != nil {
270278
errRejected = err
271279
return nil, nil
272280
}
@@ -305,9 +313,9 @@ func (m msgServer) Approve(goCtx context.Context, msg *types.MsgApprove) (*types
305313
depositTx, _ := psbt.NewFromRawBytes(bytes.NewReader([]byte(msg.DepositTx)), true)
306314
depositTxHash := depositTx.UnsignedTx.TxHash().String()
307315

308-
depositTxAlreadyExists := true
316+
authorized := true
309317
if !m.HasDepositLog(ctx, depositTxHash) {
310-
depositTxAlreadyExists = false
318+
authorized = false
311319

312320
depositLog := &types.DepositLog{
313321
Txid: depositTxHash,
@@ -326,7 +334,7 @@ func (m msgServer) Approve(goCtx context.Context, msg *types.MsgApprove) (*types
326334
depositLog.Verified = true
327335
m.SetDepositLog(ctx, depositLog)
328336

329-
// cets submission rejected
337+
// cet authorization rejected
330338
if loan.Status == types.LoanStatus_Rejected {
331339
return nil, nil
332340
}
@@ -362,39 +370,23 @@ func (m msgServer) Approve(goCtx context.Context, msg *types.MsgApprove) (*types
362370
return nil, nil
363371
}
364372

365-
liquidationPrice := sdkmath.ZeroInt()
366-
367-
// loan requested
368-
if !depositTxAlreadyExists {
369-
vaultPkScript, _ := types.GetPkScriptFromAddress(loan.VaultAddress)
370-
371-
collateralAmount := sdkmath.ZeroInt()
372-
for _, out := range depositTx.UnsignedTx.TxOut {
373-
if bytes.Equal(out.PkScript, vaultPkScript) {
374-
collateralAmount = collateralAmount.Add(sdkmath.NewInt(out.Value))
375-
}
376-
377-
poolConfig := m.GetPool(ctx, loan.PoolId).Config
378-
liquidationPrice = types.GetLiquidationPrice(collateralAmount, loan.BorrowAmount.Amount, loan.Maturity, loan.BorrowAPR, poolConfig.LiquidationThreshold)
373+
// check liquidation price if cet authorized
374+
if authorized {
375+
currentPrice, err := m.GetPrice(ctx, "BTCUSD")
376+
if err != nil {
377+
return nil, err
379378
}
380-
} else {
381-
liquidationPrice = loan.LiquidationPrice
382-
}
383379

384-
currentPrice, err := m.GetPrice(ctx, "BTCUSD")
385-
if err != nil {
386-
return nil, err
387-
}
388-
389-
// check if liquidation price reached
390-
if currentPrice.LTE(liquidationPrice.ToLegacyDec()) {
391-
errRejected = types.ErrLiquidationPriceReached
392-
return nil, nil
380+
// check if liquidation price reached
381+
if currentPrice.LTE(loan.LiquidationPrice.ToLegacyDec()) {
382+
errRejected = types.ErrLiquidationPriceReached
383+
return nil, nil
384+
}
393385
}
394386

395-
// cets submitted
396-
if depositTxAlreadyExists {
397-
if err := m.HandleApproval(ctx, msg.Relayer, depositTxHash, loan); err != nil {
387+
// approve loan if cet authorized and all deposit txs verified
388+
if authorized && m.DepositTxsVerified(ctx, loan.AuthorizationDeposits[len(loan.AuthorizationDeposits)-1].DepositTxs) {
389+
if err := m.HandleApproval(ctx, msg.Relayer, loan); err != nil {
398390
errRejected = err
399391
return nil, nil
400392
}

0 commit comments

Comments
 (0)