github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/order/keeper/order.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
     8  
     9  	"github.com/fibonacci-chain/fbc/x/order/types"
    10  	token "github.com/fibonacci-chain/fbc/x/token/types"
    11  )
    12  
    13  // TryPlaceOrder tries to charge fee & lock coins for a new order
    14  func (k Keeper) TryPlaceOrder(ctx sdk.Context, order *types.Order) (fee sdk.SysCoins, err error) {
    15  	logger := ctx.Logger().With("module", "order")
    16  	// Trying to lock coins
    17  	needLockCoins := order.NeedLockCoins()
    18  	err = k.LockCoins(ctx, order.Sender, needLockCoins, token.LockCoinsTypeQuantity)
    19  	if err != nil {
    20  		logger.Info(fmt.Sprintf("place order failed: %v, %v", err, order))
    21  		return fee, err
    22  	}
    23  
    24  	// charge fee for placing a new order
    25  	// Note: collected fees stored in cache, make sure handler will be succeed before updating cache
    26  	// Currently, after lock coins successfully, placeOrder will succeed if charging succeed
    27  	fee = GetOrderNewFee(order)
    28  
    29  	if err := k.LockCoins(ctx, order.Sender, fee, token.LockCoinsTypeFee); err != nil {
    30  		return fee, err
    31  	}
    32  
    33  	return fee, err
    34  }
    35  
    36  // PlaceOrder updates BlockOrderNum, DepthBook, execute TryPlaceOrder, and set the specified order to keeper
    37  func (k Keeper) PlaceOrder(ctx sdk.Context, order *types.Order) error {
    38  	fee, err := k.TryPlaceOrder(ctx, order)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	order.RecordOrderNewFee(fee)
    43  	k.AddFeeDetail(ctx, order.Sender, fee, types.FeeTypeOrderNew)
    44  
    45  	blockHeight := ctx.BlockHeight()
    46  	orderNum := k.GetBlockOrderNum(ctx, blockHeight)
    47  	order.OrderID = types.FormatOrderID(blockHeight, orderNum+1)
    48  
    49  	k.SetBlockOrderNum(ctx, blockHeight, orderNum+1)
    50  	k.SetOrder(ctx, order.OrderID, order)
    51  
    52  	// update depth book and orderIDsMap in cache
    53  	k.InsertOrderIntoDepthBook(order)
    54  	return nil
    55  }
    56  
    57  // ExpireOrder quits the specified order with the expired state
    58  func (k Keeper) ExpireOrder(ctx sdk.Context, order *types.Order, logger log.Logger) {
    59  	k.quitOrder(ctx, order, types.FeeTypeOrderExpire, logger)
    60  }
    61  
    62  // CancelOrder quits the specified order with the canceled state
    63  func (k Keeper) CancelOrder(ctx sdk.Context, order *types.Order, logger log.Logger) sdk.SysCoins {
    64  	return k.quitOrder(ctx, order, types.FeeTypeOrderCancel, logger)
    65  }
    66  
    67  // quitOrder unlocks & charges fee, unlocks coins, updates order, and updates DepthBook
    68  func (k Keeper) quitOrder(ctx sdk.Context, order *types.Order, feeType string, logger log.Logger) (fee sdk.SysCoins) {
    69  	switch feeType {
    70  	case types.FeeTypeOrderCancel:
    71  		order.Cancel()
    72  	case types.FeeTypeOrderExpire:
    73  		order.Expire()
    74  	default:
    75  		return
    76  	}
    77  
    78  	// unlock coins in this order & charge fee
    79  	needUnlockCoins := order.NeedUnlockCoins()
    80  	k.UnlockCoins(ctx, order.Sender, needUnlockCoins, token.LockCoinsTypeQuantity)
    81  
    82  	lockedFee := GetOrderNewFee(order)
    83  	fee = GetOrderCostFee(order, ctx)
    84  	receiveFee := lockedFee.Sub(fee)
    85  
    86  	k.UnlockCoins(ctx, order.Sender, lockedFee, token.LockCoinsTypeFee)
    87  	k.AddFeeDetail(ctx, order.Sender, receiveFee, types.FeeTypeOrderReceive)
    88  	order.RecordOrderReceiveFee(receiveFee)
    89  
    90  	err := k.AddCollectedFees(ctx, fee, order.Sender, feeType, false)
    91  
    92  	if err != nil {
    93  		logger.Error(fmt.Sprintf("failed to charge order(%s) %s fee: %v", feeType, order.OrderID, err))
    94  	}
    95  
    96  	order.Unlock()
    97  	k.SetOrder(ctx, order.OrderID, order)
    98  
    99  	// remove order from depth book cache
   100  	k.RemoveOrderFromDepthBook(order, feeType)
   101  	return fee
   102  }
   103  
   104  func (k Keeper) DropExpiredOrdersByBlockHeight(ctx sdk.Context, expiredBlockHeight int64) {
   105  	logger := ctx.Logger().With("module", "order")
   106  	store := ctx.KVStore(k.orderStoreKey)
   107  	iter := sdk.KVStorePrefixIterator(store, types.GetOrderKey(types.FormatOrderIDPrefix(expiredBlockHeight)))
   108  	defer iter.Close()
   109  	for ; iter.Valid(); iter.Next() {
   110  		var order types.Order
   111  		k.cdc.MustUnmarshalBinaryBare(iter.Value(), &order)
   112  		if order.Status == types.OrderStatusOpen && !k.IsProductLocked(ctx, order.Product) {
   113  			k.ExpireOrder(ctx, &order, logger)
   114  			logger.Info(fmt.Sprintf("order (%s) expired", order.OrderID))
   115  		}
   116  	}
   117  }