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 }