forked from fox-one/compound
-
Notifications
You must be signed in to change notification settings - Fork 0
/
supply_unpledge.go
124 lines (107 loc) · 4 KB
/
supply_unpledge.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package snapshot
import (
"compound/core"
"compound/pkg/mtg"
"context"
"errors"
"github.com/fox-one/pkg/logger"
foxuuid "github.com/fox-one/pkg/uuid"
"github.com/gofrs/uuid"
"github.com/shopspring/decimal"
)
// handle unpledge event
func (w *Payee) handleUnpledgeEvent(ctx context.Context, output *core.Output, userID, followID string, body []byte) error {
log := logger.FromContext(ctx).WithField("worker", "unpledge")
var ctokenAsset uuid.UUID
var unpledgedAmount decimal.Decimal
if _, err := mtg.Scan(body, &ctokenAsset, &unpledgedAmount); err != nil {
return w.handleRefundEvent(ctx, output, userID, followID, core.ActionTypeUnpledge, core.ErrInvalidArgument)
}
log.Infof("ctokenAssetID:%s, amount:%s", ctokenAsset.String(), unpledgedAmount)
unpledgedAmount = unpledgedAmount.Truncate(8)
ctokenAssetID := ctokenAsset.String()
market, isRecordNotFound, e := w.marketStore.FindByCToken(ctx, ctokenAssetID)
if isRecordNotFound {
log.Warningln("market not found")
return w.handleRefundEvent(ctx, output, userID, followID, core.ActionTypeUnpledge, core.ErrMarketNotFound)
}
if e != nil {
log.WithError(e).Errorln("find market error")
return e
}
if w.marketService.IsMarketClosed(ctx, market) {
return w.handleRefundEvent(ctx, output, userID, followID, core.ActionTypeUnpledge, core.ErrMarketClosed)
}
supply, isRecordNotFound, e := w.supplyStore.Find(ctx, userID, market.CTokenAssetID)
if isRecordNotFound {
log.Warningln("supply not found")
return w.handleRefundEvent(ctx, output, userID, followID, core.ActionTypeUnpledge, core.ErrSupplyNotFound)
}
if e != nil {
log.WithError(e).Errorln("find supply error")
return e
}
if unpledgedAmount.GreaterThan(supply.Collaterals) {
log.Errorln(errors.New("insufficient collaterals"))
return w.handleRefundEvent(ctx, output, userID, followID, core.ActionTypeUnpledge, core.ErrInsufficientCollaterals)
}
//accrue interest
if e = w.marketService.AccrueInterest(ctx, market, output.CreatedAt); e != nil {
log.Errorln(e)
return e
}
if e = w.marketStore.Update(ctx, market, output.ID); e != nil {
log.WithError(e).Errorln("update market error")
return e
}
// market transaction
marketTransaction := core.BuildMarketUpdateTransaction(ctx, market, foxuuid.Modify(output.TraceID, "update_market"))
if e = w.transactionStore.Create(ctx, marketTransaction); e != nil {
log.WithError(e).Errorln("create transaction error")
return e
}
// check liqudity
liquidity, e := w.accountService.CalculateAccountLiquidity(ctx, userID)
if e != nil {
log.Errorln(e)
return e
}
price := market.Price
exchangeRate, e := w.marketService.CurExchangeRate(ctx, market)
if e != nil {
log.Errorln(e)
return e
}
unpledgedTokenLiquidity := unpledgedAmount.Mul(exchangeRate).Mul(market.CollateralFactor).Mul(price)
if unpledgedTokenLiquidity.GreaterThan(liquidity) {
log.Errorln(errors.New("insufficient liquidity"))
return w.handleRefundEvent(ctx, output, userID, followID, core.ActionTypeUnpledge, core.ErrInsufficientLiquidity)
}
if output.ID > supply.Version {
supply.Collaterals = supply.Collaterals.Sub(unpledgedAmount).Truncate(16)
if e = w.supplyStore.Update(ctx, supply, output.ID); e != nil {
log.Errorln(e)
return e
}
}
// transaction
extra := core.NewTransactionExtra()
extra.Put(core.TransactionKeyCTokenAssetID, ctokenAssetID)
extra.Put(core.TransactionKeyAmount, unpledgedAmount)
extra.Put(core.TransactionKeySupply, core.ExtraSupply{
UserID: supply.UserID,
CTokenAssetID: supply.CTokenAssetID,
Collaterals: supply.Collaterals,
})
transaction := core.BuildTransactionFromOutput(ctx, userID, followID, core.ActionTypeUnpledge, output, &extra)
if e = w.transactionStore.Create(ctx, transaction); e != nil {
log.WithError(e).Errorln("create transaction error")
return e
}
// add transfer
transferAction := core.TransferAction{
Source: core.ActionTypeUnpledgeTransfer,
FollowID: followID,
}
return w.transferOut(ctx, userID, followID, output.TraceID, market.CTokenAssetID, unpledgedAmount, &transferAction)
}