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

     1  package dex
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  
     7  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     8  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
     9  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    10  	types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    11  	"github.com/fibonacci-chain/fbc/x/common"
    12  	"github.com/fibonacci-chain/fbc/x/common/perf"
    13  	"github.com/fibonacci-chain/fbc/x/dex/types"
    14  )
    15  
    16  // NewHandler handles all "dex" type messages.
    17  func NewHandler(k IKeeper) sdk.Handler {
    18  	return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
    19  		// disable dex tx handler
    20  		return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "Dex messages are not allowd.")
    21  
    22  		ctx.SetEventManager(sdk.NewEventManager())
    23  		logger := ctx.Logger().With("module", ModuleName)
    24  
    25  		var handlerFun func() (*sdk.Result, error)
    26  		var name string
    27  		switch msg := msg.(type) {
    28  		case MsgList:
    29  			name = "handleMsgList"
    30  			handlerFun = func() (*sdk.Result, error) {
    31  				return handleMsgList(ctx, k, msg, logger)
    32  			}
    33  		case MsgDeposit:
    34  			name = "handleMsgDeposit"
    35  			handlerFun = func() (*sdk.Result, error) {
    36  				return handleMsgDeposit(ctx, k, msg, logger)
    37  			}
    38  		case MsgWithdraw:
    39  			name = "handleMsgWithDraw"
    40  			handlerFun = func() (*sdk.Result, error) {
    41  				return handleMsgWithDraw(ctx, k, msg, logger)
    42  			}
    43  		case MsgTransferOwnership:
    44  			name = "handleMsgTransferOwnership"
    45  			handlerFun = func() (*sdk.Result, error) {
    46  				return handleMsgTransferOwnership(ctx, k, msg, logger)
    47  			}
    48  		case MsgConfirmOwnership:
    49  			name = "handleMsgConfirmOwnership"
    50  			handlerFun = func() (*sdk.Result, error) {
    51  				return handleMsgConfirmOwnership(ctx, k, msg, logger)
    52  			}
    53  		case MsgCreateOperator:
    54  			name = "handleMsgCreateOperator"
    55  			handlerFun = func() (*sdk.Result, error) {
    56  				return handleMsgCreateOperator(ctx, k, msg, logger)
    57  			}
    58  		case MsgUpdateOperator:
    59  			name = "handleMsgUpdateOperator"
    60  			handlerFun = func() (*sdk.Result, error) {
    61  				return handleMsgUpdateOperator(ctx, k, msg, logger)
    62  			}
    63  		default:
    64  			return types.ErrDexUnknownMsgType(msg.Type()).Result()
    65  		}
    66  
    67  		seq := perf.GetPerf().OnDeliverTxEnter(ctx, ModuleName, name)
    68  		defer perf.GetPerf().OnDeliverTxExit(ctx, ModuleName, name, seq)
    69  
    70  		res, err := handlerFun()
    71  		common.SanityCheckHandler(res, err)
    72  		return res, err
    73  	}
    74  }
    75  
    76  func handleMsgList(ctx sdk.Context, keeper IKeeper, msg MsgList, logger log.Logger) (*sdk.Result, error) {
    77  
    78  	if !keeper.GetTokenKeeper().TokenExist(ctx, msg.ListAsset) ||
    79  		!keeper.GetTokenKeeper().TokenExist(ctx, msg.QuoteAsset) {
    80  		return types.ErrTokenOfPairNotExist(msg.ListAsset, msg.QuoteAsset).Result()
    81  	}
    82  
    83  	if _, exists := keeper.GetOperator(ctx, msg.Owner); !exists {
    84  		return types.ErrUnknownOperator(msg.Owner).Result()
    85  	}
    86  
    87  	tokenPair := &TokenPair{
    88  		BaseAssetSymbol:  msg.ListAsset,
    89  		QuoteAssetSymbol: msg.QuoteAsset,
    90  		InitPrice:        msg.InitPrice,
    91  		MaxPriceDigit:    int64(DefaultMaxPriceDigitSize),
    92  		MaxQuantityDigit: int64(DefaultMaxQuantityDigitSize),
    93  		MinQuantity:      sdk.MustNewDecFromStr("0.00000001"),
    94  		Owner:            msg.Owner,
    95  		Delisting:        false,
    96  		Deposits:         DefaultTokenPairDeposit,
    97  		BlockHeight:      ctx.BlockHeight(),
    98  	}
    99  
   100  	// check whether a specific token pair exists with the symbols of base asset and quote asset
   101  	// Note: aaa_bbb and bbb_aaa are actually one token pair
   102  	if keeper.GetTokenPair(ctx, fmt.Sprintf("%s_%s", tokenPair.BaseAssetSymbol, tokenPair.QuoteAssetSymbol)) != nil ||
   103  		keeper.GetTokenPair(ctx, fmt.Sprintf("%s_%s", tokenPair.QuoteAssetSymbol, tokenPair.BaseAssetSymbol)) != nil {
   104  		return types.ErrTokenPairExisted(tokenPair.BaseAssetSymbol, tokenPair.QuoteAssetSymbol).Result()
   105  	}
   106  
   107  	// deduction fee
   108  	feeCoins := keeper.GetParams(ctx).ListFee.ToCoins()
   109  	err := keeper.GetSupplyKeeper().SendCoinsFromAccountToModule(ctx, msg.Owner, keeper.GetFeeCollector(), feeCoins)
   110  	if err != nil {
   111  		return types.ErrInsufficientFeeCoins(feeCoins).Result()
   112  	}
   113  
   114  	err2 := keeper.SaveTokenPair(ctx, tokenPair)
   115  	if err2 != nil {
   116  		return types.ErrTokenPairSaveFailed(err2.Error()).Result()
   117  	}
   118  
   119  	logger.Debug(fmt.Sprintf("successfully handleMsgList: "+
   120  		"BlockHeight: %d, Msg: %+v", ctx.BlockHeight(), msg))
   121  
   122  	ctx.EventManager().EmitEvent(
   123  		sdk.NewEvent(
   124  			sdk.EventTypeMessage,
   125  			sdk.NewAttribute("list-asset", tokenPair.BaseAssetSymbol),
   126  			sdk.NewAttribute("quote-asset", tokenPair.QuoteAssetSymbol),
   127  			sdk.NewAttribute("init-price", tokenPair.InitPrice.String()),
   128  			sdk.NewAttribute("max-price-digit", strconv.FormatInt(tokenPair.MaxPriceDigit, 10)),
   129  			sdk.NewAttribute("max-size-digit", strconv.FormatInt(tokenPair.MaxQuantityDigit, 10)),
   130  			sdk.NewAttribute("min-trade-size", tokenPair.MinQuantity.String()),
   131  			sdk.NewAttribute("delisting", fmt.Sprintf("%t", tokenPair.Delisting)),
   132  			sdk.NewAttribute(sdk.AttributeKeyFee, feeCoins.String()),
   133  		),
   134  	)
   135  
   136  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   137  }
   138  
   139  func handleMsgDeposit(ctx sdk.Context, keeper IKeeper, msg MsgDeposit, logger log.Logger) (*sdk.Result, error) {
   140  	confirmOwnership, exist := keeper.GetConfirmOwnership(ctx, msg.Product)
   141  	if exist && !ctx.BlockTime().After(confirmOwnership.Expire) {
   142  		return types.ErrIsTransferringOwner(msg.Product).Result()
   143  	}
   144  	if sdkErr := keeper.Deposit(ctx, msg.Product, msg.Depositor, msg.Amount); sdkErr != nil {
   145  		return types.ErrDepositFailed(sdkErr.Error()).Result()
   146  	}
   147  
   148  	logger.Debug(fmt.Sprintf("successfully handleMsgDeposit: "+
   149  		"BlockHeight: %d, Msg: %+v", ctx.BlockHeight(), msg))
   150  
   151  	ctx.EventManager().EmitEvent(
   152  		sdk.NewEvent(
   153  			sdk.EventTypeMessage,
   154  			sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
   155  		),
   156  	)
   157  
   158  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   159  
   160  }
   161  
   162  func handleMsgWithDraw(ctx sdk.Context, keeper IKeeper, msg MsgWithdraw, logger log.Logger) (*sdk.Result, error) {
   163  	if sdkErr := keeper.Withdraw(ctx, msg.Product, msg.Depositor, msg.Amount); sdkErr != nil {
   164  		return nil, sdkErr
   165  	}
   166  
   167  	logger.Debug(fmt.Sprintf("successfully handleMsgWithDraw: "+
   168  		"BlockHeight: %d, Msg: %+v", ctx.BlockHeight(), msg))
   169  
   170  	ctx.EventManager().EmitEvent(
   171  		sdk.NewEvent(
   172  			sdk.EventTypeMessage,
   173  			sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
   174  		),
   175  	)
   176  
   177  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   178  }
   179  
   180  func handleMsgTransferOwnership(ctx sdk.Context, keeper IKeeper, msg MsgTransferOwnership,
   181  	logger log.Logger) (*sdk.Result, error) {
   182  	// validate
   183  	tokenPair := keeper.GetTokenPair(ctx, msg.Product)
   184  	if tokenPair == nil {
   185  		return types.ErrTokenPairNotFound(msg.Product).Result()
   186  	}
   187  	if !tokenPair.Owner.Equals(msg.FromAddress) {
   188  		return types.ErrUnauthorized(msg.FromAddress.String(), msg.Product).Result()
   189  	}
   190  	if _, exist := keeper.GetOperator(ctx, msg.ToAddress); !exist {
   191  		return types.ErrUnknownOperator(msg.ToAddress).Result()
   192  	}
   193  	confirmOwnership, exist := keeper.GetConfirmOwnership(ctx, msg.Product)
   194  	if exist && !ctx.BlockTime().After(confirmOwnership.Expire) {
   195  		return types.ErrRepeatedTransferOwner(msg.Product).Result()
   196  	}
   197  
   198  	// withdraw
   199  	if tokenPair.Deposits.IsPositive() {
   200  		if err := keeper.Withdraw(ctx, msg.Product, msg.FromAddress, tokenPair.Deposits); err != nil {
   201  			return types.ErrWithdrawFailed(err.Error()).Result()
   202  		}
   203  	}
   204  
   205  	// deduction fee
   206  	feeCoins := keeper.GetParams(ctx).TransferOwnershipFee.ToCoins()
   207  	err := keeper.GetSupplyKeeper().SendCoinsFromAccountToModule(ctx, msg.FromAddress, keeper.GetFeeCollector(), feeCoins)
   208  	if err != nil {
   209  		return types.ErrInsufficientFeeCoins(feeCoins).Result()
   210  	}
   211  
   212  	// set ConfirmOwnership
   213  	expireTime := ctx.BlockTime().Add(keeper.GetParams(ctx).OwnershipConfirmWindow)
   214  	confirmOwnership = &types.ConfirmOwnership{
   215  		Product:     msg.Product,
   216  		FromAddress: msg.FromAddress,
   217  		ToAddress:   msg.ToAddress,
   218  		Expire:      expireTime,
   219  	}
   220  	keeper.SetConfirmOwnership(ctx, confirmOwnership)
   221  
   222  	logger.Debug(fmt.Sprintf("successfully handleMsgTransferOwnership: "+
   223  		"BlockHeight: %d, Msg: %+v", ctx.BlockHeight(), msg))
   224  
   225  	ctx.EventManager().EmitEvent(
   226  		sdk.NewEvent(
   227  			sdk.EventTypeMessage,
   228  			sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
   229  			sdk.NewAttribute(sdk.AttributeKeyFee, feeCoins.String()),
   230  		),
   231  	)
   232  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   233  }
   234  
   235  func handleMsgConfirmOwnership(ctx sdk.Context, keeper IKeeper, msg MsgConfirmOwnership, logger log.Logger) (*sdk.Result, error) {
   236  	confirmOwnership, exist := keeper.GetConfirmOwnership(ctx, msg.Product)
   237  	if !exist {
   238  		return types.ErrGetConfirmOwnershipNotExist(msg.Address.String()).Result()
   239  	}
   240  	if ctx.BlockTime().After(confirmOwnership.Expire) {
   241  		// delete ownership confirming information
   242  		keeper.DeleteConfirmOwnership(ctx, confirmOwnership.Product)
   243  		return types.ErrIsTransferOwnerExpired(confirmOwnership.Expire.String()).Result()
   244  	}
   245  	if !confirmOwnership.ToAddress.Equals(msg.Address) {
   246  		return types.ErrUnauthorized(confirmOwnership.ToAddress.String(), msg.Product).Result()
   247  	}
   248  
   249  	tokenPair := keeper.GetTokenPair(ctx, msg.Product)
   250  	if tokenPair == nil {
   251  		return types.ErrTokenPairNotFound(msg.Product).Result()
   252  	}
   253  	// transfer ownership
   254  	tokenPair.Owner = msg.Address
   255  	keeper.UpdateTokenPair(ctx, msg.Product, tokenPair)
   256  	keeper.UpdateUserTokenPair(ctx, msg.Product, confirmOwnership.FromAddress, msg.Address)
   257  	// delete ownership confirming information
   258  	keeper.DeleteConfirmOwnership(ctx, confirmOwnership.Product)
   259  
   260  	logger.Debug(fmt.Sprintf("successfully handleMsgConfirmOwnership: "+
   261  		"BlockHeight: %d, Msg: %+v", ctx.BlockHeight(), msg))
   262  
   263  	ctx.EventManager().EmitEvent(
   264  		sdk.NewEvent(
   265  			sdk.EventTypeMessage,
   266  			sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
   267  		),
   268  	)
   269  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   270  }
   271  
   272  func handleMsgCreateOperator(ctx sdk.Context, keeper IKeeper, msg MsgCreateOperator, logger log.Logger) (*sdk.Result, error) {
   273  
   274  	logger.Debug(fmt.Sprintf("handleMsgCreateOperator msg: %+v", msg))
   275  
   276  	if _, isExist := keeper.GetOperator(ctx, msg.Owner); isExist {
   277  		return types.ErrExistOperator(msg.Owner).Result()
   278  	}
   279  	operator := types.DEXOperator{
   280  		Address:            msg.Owner,
   281  		HandlingFeeAddress: msg.HandlingFeeAddress,
   282  		Website:            msg.Website,
   283  		InitHeight:         ctx.BlockHeight(),
   284  		TxHash:             fmt.Sprintf("%X", types2.Tx(ctx.TxBytes()).Hash(ctx.BlockHeight())),
   285  	}
   286  	keeper.SetOperator(ctx, operator)
   287  
   288  	// deduction fee
   289  	feeCoins := keeper.GetParams(ctx).RegisterOperatorFee.ToCoins()
   290  	err := keeper.GetSupplyKeeper().SendCoinsFromAccountToModule(ctx, msg.Owner, keeper.GetFeeCollector(), feeCoins)
   291  	if err != nil {
   292  		return common.ErrInsufficientCoins(DefaultParamspace, err.Error()).Result()
   293  	}
   294  
   295  	ctx.EventManager().EmitEvent(
   296  		sdk.NewEvent(
   297  			sdk.EventTypeMessage,
   298  			sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
   299  			sdk.NewAttribute(sdk.AttributeKeyFee, feeCoins.String()),
   300  		),
   301  	)
   302  
   303  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   304  }
   305  
   306  func handleMsgUpdateOperator(ctx sdk.Context, keeper IKeeper, msg MsgUpdateOperator, logger log.Logger) (*sdk.Result, error) {
   307  
   308  	logger.Debug(fmt.Sprintf("handleMsgUpdateOperator msg: %+v", msg))
   309  
   310  	operator, isExist := keeper.GetOperator(ctx, msg.Owner)
   311  	if !isExist {
   312  		return types.ErrUnknownOperator(msg.Owner).Result()
   313  	}
   314  	if !operator.Address.Equals(msg.Owner) {
   315  		return types.ErrUnauthorizedOperator(operator.Address.String(), msg.Owner.String()).Result()
   316  	}
   317  
   318  	operator.HandlingFeeAddress = msg.HandlingFeeAddress
   319  	operator.Website = msg.Website
   320  
   321  	keeper.SetOperator(ctx, operator)
   322  
   323  	ctx.EventManager().EmitEvent(
   324  		sdk.NewEvent(
   325  			sdk.EventTypeMessage,
   326  			sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
   327  		),
   328  	)
   329  
   330  	return &sdk.Result{Events: ctx.EventManager().Events()}, nil
   331  }