-
Notifications
You must be signed in to change notification settings - Fork 179
/
order.go
117 lines (95 loc) · 3.87 KB
/
order.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
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/okex/okexchain/x/order/types"
token "github.com/okex/okexchain/x/token/types"
)
// TryPlaceOrder tries to charge fee & lock coins for a new order
func (k Keeper) TryPlaceOrder(ctx sdk.Context, order *types.Order) (fee sdk.SysCoins, err error) {
logger := ctx.Logger().With("module", "order")
// Trying to lock coins
needLockCoins := order.NeedLockCoins()
err = k.LockCoins(ctx, order.Sender, needLockCoins, token.LockCoinsTypeQuantity)
if err != nil {
logger.Info(fmt.Sprintf("place order failed: %v, %v", err, order))
return fee, err
}
// charge fee for placing a new order
// Note: collected fees stored in cache, make sure handler will be succeed before updating cache
// Currently, after lock coins successfully, placeOrder will succeed if charging succeed
fee = GetOrderNewFee(order)
if err := k.LockCoins(ctx, order.Sender, fee, token.LockCoinsTypeFee); err != nil {
return fee, err
}
return fee, err
}
// PlaceOrder updates BlockOrderNum, DepthBook, execute TryPlaceOrder, and set the specified order to keeper
func (k Keeper) PlaceOrder(ctx sdk.Context, order *types.Order) error {
fee, err := k.TryPlaceOrder(ctx, order)
if err != nil {
return err
}
order.RecordOrderNewFee(fee)
k.AddFeeDetail(ctx, order.Sender, fee, types.FeeTypeOrderNew)
blockHeight := ctx.BlockHeight()
orderNum := k.GetBlockOrderNum(ctx, blockHeight)
order.OrderID = types.FormatOrderID(blockHeight, orderNum+1)
k.SetBlockOrderNum(ctx, blockHeight, orderNum+1)
k.SetOrder(ctx, order.OrderID, order)
// update depth book and orderIDsMap in cache
k.InsertOrderIntoDepthBook(order)
return nil
}
// ExpireOrder quits the specified order with the expired state
func (k Keeper) ExpireOrder(ctx sdk.Context, order *types.Order, logger log.Logger) {
k.quitOrder(ctx, order, types.FeeTypeOrderExpire, logger)
}
// CancelOrder quits the specified order with the canceled state
func (k Keeper) CancelOrder(ctx sdk.Context, order *types.Order, logger log.Logger) sdk.SysCoins {
return k.quitOrder(ctx, order, types.FeeTypeOrderCancel, logger)
}
// quitOrder unlocks & charges fee, unlocks coins, updates order, and updates DepthBook
func (k Keeper) quitOrder(ctx sdk.Context, order *types.Order, feeType string, logger log.Logger) (fee sdk.SysCoins) {
switch feeType {
case types.FeeTypeOrderCancel:
order.Cancel()
case types.FeeTypeOrderExpire:
order.Expire()
default:
return
}
// unlock coins in this order & charge fee
needUnlockCoins := order.NeedUnlockCoins()
k.UnlockCoins(ctx, order.Sender, needUnlockCoins, token.LockCoinsTypeQuantity)
lockedFee := GetOrderNewFee(order)
fee = GetOrderCostFee(order, ctx)
receiveFee := lockedFee.Sub(fee)
k.UnlockCoins(ctx, order.Sender, lockedFee, token.LockCoinsTypeFee)
k.AddFeeDetail(ctx, order.Sender, receiveFee, types.FeeTypeOrderReceive)
order.RecordOrderReceiveFee(receiveFee)
err := k.AddCollectedFees(ctx, fee, order.Sender, feeType, false)
if err != nil {
logger.Error(fmt.Sprintf("failed to charge order(%s) %s fee: %v", feeType, order.OrderID, err))
}
order.Unlock()
k.SetOrder(ctx, order.OrderID, order)
// remove order from depth book cache
k.RemoveOrderFromDepthBook(order, feeType)
return fee
}
func (k Keeper) DropExpiredOrdersByBlockHeight(ctx sdk.Context, expiredBlockHeight int64) {
logger := ctx.Logger().With("module", "order")
store := ctx.KVStore(k.orderStoreKey)
iter := sdk.KVStorePrefixIterator(store, types.GetOrderKey(types.FormatOrderIDPrefix(expiredBlockHeight)))
defer iter.Close()
for ; iter.Valid(); iter.Next() {
var order types.Order
k.cdc.MustUnmarshalBinaryBare(iter.Value(), &order)
if order.Status == types.OrderStatusOpen && !k.IsProductLocked(ctx, order.Product) {
k.ExpireOrder(ctx, &order, logger)
logger.Info(fmt.Sprintf("order (%s) expired", order.OrderID))
}
}
}