github.com/KiraCore/sekai@v0.3.43/x/layer2/keeper/msg_server.go (about) 1 package keeper 2 3 import ( 4 "context" 5 6 govtypes "github.com/KiraCore/sekai/x/gov/types" 7 "github.com/KiraCore/sekai/x/layer2/types" 8 sdk "github.com/cosmos/cosmos-sdk/types" 9 ) 10 11 type msgServer struct { 12 keeper Keeper 13 } 14 15 // NewMsgServerImpl returns an implementation of the bank MsgServer interface 16 // for the provided Keeper. 17 func NewMsgServerImpl(keeper Keeper) types.MsgServer { 18 return &msgServer{ 19 keeper: keeper, 20 } 21 } 22 23 var _ types.MsgServer = msgServer{} 24 25 func (k msgServer) CreateDappProposal(goCtx context.Context, msg *types.MsgCreateDappProposal) (*types.MsgCreateDappProposalResponse, error) { 26 ctx := sdk.UnwrapSDKContext(goCtx) 27 28 properties := k.keeper.gk.GetNetworkProperties(ctx) 29 addr := sdk.MustAccAddressFromBech32(msg.Sender) 30 31 // permission check PermCreateDappProposalWithoutBond 32 isAllowed := k.keeper.CheckIfAllowedPermission(ctx, addr, govtypes.PermCreateDappProposalWithoutBond) 33 if !isAllowed { 34 minDappBond := properties.MinDappBond 35 if msg.Bond.Denom != k.keeper.DefaultDenom(ctx) { 36 return nil, types.ErrInvalidDappBondDenom 37 } 38 // check 1% of properties.MinDappBond 39 if msg.Bond.Amount.Mul(sdk.NewInt(100)).LT(sdk.NewInt(int64(minDappBond)).Mul(sdk.NewInt(1000_000))) { 40 return nil, types.ErrLowAmountToCreateDappProposal 41 } 42 } 43 44 // send initial bond to module account 45 if msg.Bond.IsPositive() { 46 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.Coins{msg.Bond}) 47 if err != nil { 48 return nil, err 49 } 50 } 51 52 dapp := k.keeper.GetDapp(ctx, msg.Dapp.Name) 53 if dapp.Name != "" { 54 return nil, types.ErrDappAlreadyExists 55 } 56 57 // create dapp object 58 msg.Dapp.TotalBond = msg.Bond 59 msg.Dapp.CreationTime = uint64(ctx.BlockTime().Unix()) 60 msg.Dapp.Status = types.Bootstrap 61 k.keeper.SetDapp(ctx, msg.Dapp) 62 k.keeper.SetUserDappBond(ctx, types.UserDappBond{ 63 DappName: msg.Dapp.Name, 64 User: msg.Sender, 65 Bond: msg.Bond, 66 }) 67 68 return &types.MsgCreateDappProposalResponse{}, nil 69 } 70 71 func (k msgServer) BondDappProposal(goCtx context.Context, msg *types.MsgBondDappProposal) (*types.MsgBondDappProposalResponse, error) { 72 ctx := sdk.UnwrapSDKContext(goCtx) 73 74 dapp := k.keeper.GetDapp(ctx, msg.DappName) 75 if dapp.Name == "" { 76 return nil, types.ErrDappDoesNotExist 77 } 78 79 if k.keeper.DefaultDenom(ctx) != msg.Bond.Denom { 80 return nil, types.ErrInvalidDappBondDenom 81 } 82 83 // send initial bond to module account 84 addr := sdk.MustAccAddressFromBech32(msg.Sender) 85 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.Coins{msg.Bond}) 86 if err != nil { 87 return nil, err 88 } 89 90 properties := k.keeper.gk.GetNetworkProperties(ctx) 91 if dapp.TotalBond.Amount.GTE(sdk.NewInt(int64(properties.MaxDappBond)).Mul(sdk.NewInt(1000_000))) { 92 return nil, types.ErrMaxDappBondReached 93 } 94 95 dapp.TotalBond = dapp.TotalBond.Add(msg.Bond) 96 k.keeper.SetDapp(ctx, dapp) 97 98 userDappBond := k.keeper.GetUserDappBond(ctx, msg.DappName, msg.Sender) 99 if userDappBond.User != "" { 100 userDappBond.Bond = userDappBond.Bond.Add(msg.Bond) 101 } else { 102 userDappBond = types.UserDappBond{ 103 User: msg.Sender, 104 DappName: msg.DappName, 105 Bond: msg.Bond, 106 } 107 } 108 k.keeper.SetUserDappBond(ctx, userDappBond) 109 110 return &types.MsgBondDappProposalResponse{}, nil 111 } 112 113 func (k msgServer) ReclaimDappBondProposal(goCtx context.Context, msg *types.MsgReclaimDappBondProposal) (*types.MsgReclaimDappBondProposalResponse, error) { 114 ctx := sdk.UnwrapSDKContext(goCtx) 115 116 userDappBond := k.keeper.GetUserDappBond(ctx, msg.DappName, msg.Sender) 117 if userDappBond.DappName == "" { 118 return nil, types.ErrUserDappBondDoesNotExist 119 } 120 if userDappBond.Bond.Denom != msg.Bond.Denom { 121 return nil, types.ErrInvalidDappBondDenom 122 } 123 if userDappBond.Bond.Amount.LT(msg.Bond.Amount) { 124 return nil, types.ErrNotEnoughUserDappBond 125 } 126 127 userDappBond.Bond.Amount = userDappBond.Bond.Amount.Sub(msg.Bond.Amount) 128 k.keeper.SetUserDappBond(ctx, userDappBond) 129 130 // send tokens back to user 131 addr := sdk.MustAccAddressFromBech32(msg.Sender) 132 err := k.keeper.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, sdk.Coins{msg.Bond}) 133 if err != nil { 134 return nil, err 135 } 136 137 return &types.MsgReclaimDappBondProposalResponse{}, nil 138 } 139 140 func (k msgServer) JoinDappVerifierWithBond(goCtx context.Context, msg *types.MsgJoinDappVerifierWithBond) (*types.MsgJoinDappVerifierWithBondResponse, error) { 141 ctx := sdk.UnwrapSDKContext(goCtx) 142 143 dapp := k.keeper.GetDapp(ctx, msg.DappName) 144 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 145 if operator.DappName != "" && operator.Verifier { 146 return nil, types.ErrAlreadyADappVerifier 147 } 148 149 properties := k.keeper.gk.GetNetworkProperties(ctx) 150 verifierBond := properties.DappVerifierBond 151 totalSupply := dapp.GetLpTokenSupply() 152 dappBondLpToken := dapp.LpToken() 153 lpTokenAmount := sdk.NewDecFromInt(totalSupply).Mul(verifierBond).RoundInt() 154 verifierBondCoins := sdk.NewCoins(sdk.NewCoin(dappBondLpToken, lpTokenAmount)) 155 addr := sdk.MustAccAddressFromBech32(msg.Interx) 156 if verifierBondCoins.IsAllPositive() { 157 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, verifierBondCoins) 158 if err != nil { 159 return nil, err 160 } 161 } 162 163 if operator.DappName == "" { 164 operator = types.DappOperator{ 165 DappName: msg.DappName, 166 Interx: msg.Interx, 167 Operator: msg.Sender, 168 Executor: false, 169 Verifier: true, 170 Status: types.OperatorActive, 171 BondedLpAmount: lpTokenAmount, 172 } 173 } else { 174 operator.Verifier = true 175 operator.BondedLpAmount = lpTokenAmount 176 } 177 k.keeper.SetDappOperator(ctx, operator) 178 return &types.MsgJoinDappVerifierWithBondResponse{}, nil 179 } 180 181 func (k msgServer) ExitDapp(goCtx context.Context, msg *types.MsgExitDapp) (*types.MsgExitDappResponse, error) { 182 ctx := sdk.UnwrapSDKContext(goCtx) 183 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 184 if operator.DappName == "" { 185 return nil, types.ErrNotDappOperator 186 } 187 188 if operator.Status == types.OperatorJailed { 189 return nil, types.ErrOperatorJailed 190 } 191 if operator.Status == types.OperatorExiting { 192 return nil, types.ErrOperatorAlreadyExiting 193 } 194 195 operator.Status = types.OperatorExiting 196 k.keeper.SetDappOperator(ctx, operator) 197 198 return &types.MsgExitDappResponse{}, nil 199 } 200 201 func (k msgServer) PauseDappTx(goCtx context.Context, msg *types.MsgPauseDappTx) (*types.MsgPauseDappTxResponse, error) { 202 ctx := sdk.UnwrapSDKContext(goCtx) 203 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 204 if operator.DappName == "" { 205 return nil, types.ErrNotDappOperator 206 } 207 if operator.Status != types.OperatorActive { 208 return nil, types.ErrDappOperatorNotActive 209 } 210 operator.Status = types.OperatorPaused 211 k.keeper.SetDappOperator(ctx, operator) 212 213 // TODO: if the validator status changes to paused, inactive or jailed then his executor status for ALL dApps should 214 // also change to the same paused, inactive or jailed status so that all other executors can be informed that 215 // a specific node operator is not available and will miss his execution round. 216 217 return &types.MsgPauseDappTxResponse{}, nil 218 } 219 220 func (k msgServer) UnPauseDappTx(goCtx context.Context, msg *types.MsgUnPauseDappTx) (*types.MsgUnPauseDappTxResponse, error) { 221 ctx := sdk.UnwrapSDKContext(goCtx) 222 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 223 if operator.DappName == "" { 224 return nil, types.ErrNotDappOperator 225 } 226 if operator.Status != types.OperatorPaused { 227 return nil, types.ErrDappOperatorNotPaused 228 } 229 operator.Status = types.OperatorActive 230 k.keeper.SetDappOperator(ctx, operator) 231 232 return &types.MsgUnPauseDappTxResponse{}, nil 233 } 234 235 func (k msgServer) ReactivateDappTx(goCtx context.Context, msg *types.MsgReactivateDappTx) (*types.MsgReactivateDappTxResponse, error) { 236 ctx := sdk.UnwrapSDKContext(goCtx) 237 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 238 if operator.DappName == "" { 239 return nil, types.ErrNotDappOperator 240 } 241 if operator.Status != types.OperatorInactive { 242 return nil, types.ErrDappOperatorNotInActive 243 } 244 operator.Status = types.OperatorActive 245 k.keeper.SetDappOperator(ctx, operator) 246 247 return &types.MsgReactivateDappTxResponse{}, nil 248 } 249 250 func (k msgServer) ExecuteDappTx(goCtx context.Context, msg *types.MsgExecuteDappTx) (*types.MsgExecuteDappTxResponse, error) { 251 ctx := sdk.UnwrapSDKContext(goCtx) 252 session := k.keeper.GetDappSession(ctx, msg.DappName) 253 if session.DappName == "" { 254 return nil, types.ErrNoDappSessionExists 255 } 256 257 if session.NextSession.Leader != msg.Sender { 258 return nil, types.ErrNotDappSessionLeader 259 } 260 session.NextSession.Gateway = msg.Gateway 261 session.NextSession.Status = types.SessionOngoing 262 263 if session.CurrSession == nil { 264 session.CurrSession = session.NextSession 265 k.keeper.CreateNewSession(ctx, msg.DappName, session.CurrSession.Leader) 266 } 267 268 return &types.MsgExecuteDappTxResponse{}, nil 269 } 270 271 func (k msgServer) TransitionDappTx(goCtx context.Context, msg *types.MsgTransitionDappTx) (*types.MsgTransitionDappTxResponse, error) { 272 ctx := sdk.UnwrapSDKContext(goCtx) 273 274 dapp := k.keeper.GetDapp(ctx, msg.DappName) 275 if dapp.Name != "" { 276 return nil, types.ErrDappDoesNotExist 277 } 278 279 if msg.Version != dapp.Version() { 280 return nil, types.ErrInvalidDappVersion 281 } 282 283 session := k.keeper.GetDappSession(ctx, msg.DappName) 284 if session.DappName == "" { 285 return nil, types.ErrDappSessionDoesNotExist 286 } 287 session.NextSession.StatusHash = msg.StatusHash 288 session.NextSession.OnchainMessages = msg.OnchainMessages 289 k.keeper.SetDappSession(ctx, session) 290 291 return &types.MsgTransitionDappTxResponse{}, nil 292 } 293 294 func (k msgServer) DenounceLeaderTx(goCtx context.Context, msg *types.MsgDenounceLeaderTx) (*types.MsgDenounceLeaderTxResponse, error) { 295 ctx := sdk.UnwrapSDKContext(goCtx) 296 297 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 298 if !operator.Verifier { 299 return nil, types.ErrNotDappVerifier 300 } 301 302 session := k.keeper.GetDappSession(ctx, msg.DappName) 303 if session.CurrSession == nil || session.CurrSession.StatusHash == "" { 304 return nil, types.ErrVerificationNotAllowedOnEmptySession 305 } 306 if session.CurrSession.Leader == msg.Sender { 307 return nil, types.ErrLeaderCannotEvaluateSelfSubmission 308 } 309 310 dapp := k.keeper.GetDapp(ctx, msg.DappName) 311 if dapp.Name != "" { 312 return nil, types.ErrDappDoesNotExist 313 } 314 315 if msg.Version != dapp.Version() { 316 return nil, types.ErrInvalidDappVersion 317 } 318 319 // TODO: update it to be put on session 320 k.keeper.SetDappLeaderDenouncement(ctx, types.DappLeaderDenouncement{ 321 DappName: msg.DappName, 322 Leader: msg.Leader, 323 Sender: msg.Sender, 324 Denouncement: msg.DenounceText, 325 }) 326 327 return &types.MsgDenounceLeaderTxResponse{}, nil 328 } 329 330 func (k msgServer) ApproveDappTransitionTx(goCtx context.Context, msg *types.MsgApproveDappTransitionTx) (*types.MsgApproveDappTransitionTxResponse, error) { 331 ctx := sdk.UnwrapSDKContext(goCtx) 332 333 dapp := k.keeper.GetDapp(ctx, msg.DappName) 334 if dapp.Name != "" { 335 return nil, types.ErrDappDoesNotExist 336 } 337 338 if msg.Version != dapp.Version() { 339 return nil, types.ErrInvalidDappVersion 340 } 341 342 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 343 if !operator.Verifier { 344 return nil, types.ErrNotDappVerifier 345 } 346 347 session := k.keeper.GetDappSession(ctx, msg.DappName) 348 if session.CurrSession == nil || session.CurrSession.StatusHash == "" { 349 return nil, types.ErrVerificationNotAllowedOnEmptySession 350 } 351 if session.CurrSession.Leader == msg.Sender { 352 return nil, types.ErrLeaderCannotEvaluateSelfSubmission 353 } 354 k.keeper.SetDappSessionApproval(ctx, types.DappSessionApproval{ 355 DappName: msg.DappName, 356 Approver: msg.Sender, 357 IsApproved: true, 358 }) 359 360 // TODO: check after full implementation 361 // The current session status can change to `accepted` if and only if 2/3 of executors who are NOT a leader send 362 // `approve-dapp-transition-tx` and no verifiers submitted the evidence of faults requesting the application to be halted, 363 // additionally the total number of approvals must be no less then `verifiers_min`. 364 // It might happen that the application will only have a single executor, 365 // meaning that there is always an insufficient number of verifiers to approve the transition. 366 // In such cases where only one executor of the dApp exists, the approval of **NO LESS THAN** 2/3 of ALL active verifiers is required 367 // for the session state to change into `accepted` (the `verifiers_min` rule also applies). 368 369 // if more than 2/3 verify, convert to accepted 370 verifiers := k.keeper.GetDappVerifiers(ctx, msg.DappName) 371 approvals := k.keeper.GetDappSessionApprovals(ctx, msg.DappName) 372 if len(verifiers)*2/3 <= len(approvals) { 373 session.CurrSession.Status = types.SessionAccepted 374 k.keeper.SetDappSession(ctx, session) 375 k.keeper.CreateNewSession(ctx, msg.DappName, session.NextSession.Leader) 376 377 isApprover := make(map[string]bool) 378 for _, approval := range approvals { 379 isApprover[approval.Approver] = true 380 } 381 382 // dapp operator rank management 383 executor := k.keeper.GetDappOperator(ctx, session.DappName, session.CurrSession.Leader) 384 k.keeper.HandleSessionParticipation(ctx, executor, true) 385 for _, verifier := range verifiers { 386 k.keeper.HandleSessionParticipation(ctx, verifier, isApprover[verifier.Operator]) 387 } 388 } 389 390 return &types.MsgApproveDappTransitionTxResponse{}, nil 391 } 392 393 func (k msgServer) RejectDappTransitionTx(goCtx context.Context, msg *types.MsgRejectDappTransitionTx) (*types.MsgRejectDappTransitionTxResponse, error) { 394 ctx := sdk.UnwrapSDKContext(goCtx) 395 operator := k.keeper.GetDappOperator(ctx, msg.DappName, msg.Sender) 396 if !operator.Verifier { 397 return nil, types.ErrNotDappVerifier 398 } 399 400 session := k.keeper.GetDappSession(ctx, msg.DappName) 401 if session.CurrSession.Leader == msg.Sender { 402 return nil, types.ErrLeaderCannotEvaluateSelfSubmission 403 } 404 405 dapp := k.keeper.GetDapp(ctx, msg.DappName) 406 if dapp.Name != "" { 407 return nil, types.ErrDappDoesNotExist 408 } 409 410 if msg.Version != dapp.Version() { 411 return nil, types.ErrInvalidDappVersion 412 } 413 414 if session.CurrSession == nil || session.CurrSession.StatusHash == "" { 415 return nil, types.ErrVerificationNotAllowedOnEmptySession 416 } 417 418 // halt the session 419 session.CurrSession.Status = types.SessionHalted 420 k.keeper.SetDappSession(ctx, session) 421 422 k.keeper.SetDappSessionApproval(ctx, types.DappSessionApproval{ 423 DappName: msg.DappName, 424 Approver: msg.Sender, 425 IsApproved: true, 426 }) 427 428 return &types.MsgRejectDappTransitionTxResponse{}, nil 429 } 430 431 func (k Keeper) GetCoinsFromBridgeBalance(ctx sdk.Context, balances []types.BridgeBalance) sdk.Coins { 432 coins := sdk.Coins{} 433 for _, balance := range balances { 434 token := k.GetBridgeToken(ctx, balance.BridgeTokenIndex) 435 if token.Denom == "" { 436 continue 437 } 438 coins = coins.Add(sdk.NewCoin(token.Denom, balance.Amount)) 439 } 440 return coins 441 } 442 443 func AddBridgeBalance(balances []types.BridgeBalance, addition []types.BridgeBalance) []types.BridgeBalance { 444 indexMap := make(map[uint64]int) 445 for i, balance := range balances { 446 indexMap[balance.BridgeTokenIndex] = i 447 } 448 449 for _, balance := range addition { 450 i, ok := indexMap[balance.BridgeTokenIndex] 451 if ok { 452 balances[i].Amount = balances[i].Amount.Add(balance.Amount) 453 } else { 454 balances = append(balances, balance) 455 } 456 } 457 return balances 458 } 459 460 func SubBridgeBalance(balances []types.BridgeBalance, removal []types.BridgeBalance) ([]types.BridgeBalance, error) { 461 indexMap := make(map[uint64]int) 462 for i, balance := range balances { 463 indexMap[balance.BridgeTokenIndex] = i 464 } 465 466 for _, balance := range removal { 467 i, ok := indexMap[balance.BridgeTokenIndex] 468 if ok { 469 balances[i].Amount = balances[i].Amount.Sub(balance.Amount) 470 if balances[i].Amount.IsNegative() { 471 return balances, types.ErrNegativeBridgeBalance 472 } 473 } else { 474 return balances, types.ErrNegativeBridgeBalance 475 } 476 } 477 return balances, nil 478 } 479 480 func (k msgServer) TransferDappTx(goCtx context.Context, msg *types.MsgTransferDappTx) (*types.MsgTransferDappTxResponse, error) { 481 ctx := sdk.UnwrapSDKContext(goCtx) 482 sender := sdk.MustAccAddressFromBech32(msg.Sender) 483 helper := k.keeper.GetBridgeRegistrarHelper(ctx) 484 nextXid := helper.NextXam 485 for _, xam := range msg.Requests { 486 coins := k.keeper.GetCoinsFromBridgeBalance(ctx, xam.Amounts) 487 if !coins.Empty() { 488 sa := k.keeper.GetBridgeAccount(ctx, xam.SourceAccount) 489 if xam.SourceDapp == 0 { // direct deposit from user 490 if sa.Address == "" { 491 sa.Address = msg.Sender 492 sa.Index = helper.NextUser 493 sa.DappName = "" 494 helper.NextUser += 1 495 k.keeper.SetBridgeRegistrarHelper(ctx, helper) 496 } 497 if sa.Address != msg.Sender { 498 return nil, types.ErrInvalidBridgeDepositMessage 499 } 500 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, coins) 501 if err != nil { 502 return nil, err 503 } 504 sa.Balances = AddBridgeBalance(sa.Balances, xam.Amounts) 505 k.keeper.SetBridgeAccount(ctx, sa) 506 } else if xam.DestDapp == 0 { // withdrawal to user account 507 ba := k.keeper.GetBridgeAccount(ctx, xam.DestBeneficiary) 508 if ba.Address != msg.Sender { 509 return nil, types.ErrInvalidBridgeWithdrawalMessage 510 } 511 err := k.keeper.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, coins) 512 if err != nil { 513 return nil, err 514 } 515 sa.Balances, err = SubBridgeBalance(sa.Balances, xam.Amounts) 516 if err != nil { 517 return nil, err 518 } 519 k.keeper.SetBridgeAccount(ctx, sa) 520 } else { 521 // check accuracy of source in case of dapp 522 sa := k.keeper.GetBridgeAccount(ctx, xam.SourceAccount) 523 if sa.Address != msg.Sender { 524 return nil, types.ErrInvalidBridgeSourceAccount 525 } 526 } 527 } 528 k.keeper.SetXAM(ctx, types.XAM{ 529 Req: xam, 530 Res: types.XAMResponse{ 531 Xid: nextXid, 532 Irc: 0, 533 Src: 0, 534 Drc: 0, 535 Irm: 0, 536 Srm: 0, 537 Drm: 0, 538 }, 539 }) 540 nextXid += 1 541 } 542 helper.NextXam = nextXid 543 k.keeper.SetBridgeRegistrarHelper(ctx, helper) 544 545 return &types.MsgTransferDappTxResponse{}, nil 546 } 547 548 func (k msgServer) AckTransferDappTx(goCtx context.Context, msg *types.MsgAckTransferDappTx) (*types.MsgAckTransferDappTxResponse, error) { 549 ctx := sdk.UnwrapSDKContext(goCtx) 550 for _, res := range msg.Responses { 551 xam := k.keeper.GetXAM(ctx, res.Xid) 552 if xam.Res.Drc != 0 { // response already set 553 continue 554 } 555 xam.Res = res 556 k.keeper.SetXAM(ctx, xam) 557 // handle token transfer when response is okay 558 if res.Drc == 200 { // status okay 559 var err error 560 sa := k.keeper.GetBridgeAccount(ctx, xam.Req.SourceAccount) 561 sa.Balances, err = SubBridgeBalance(sa.Balances, xam.Req.Amounts) 562 if err != nil { 563 return nil, err 564 } 565 k.keeper.SetBridgeAccount(ctx, sa) 566 da := k.keeper.GetBridgeAccount(ctx, xam.Req.DestBeneficiary) 567 da.Balances = AddBridgeBalance(sa.Balances, xam.Req.Amounts) 568 if err != nil { 569 return nil, err 570 } 571 k.keeper.SetBridgeAccount(ctx, da) 572 } 573 } 574 575 return &types.MsgAckTransferDappTxResponse{}, nil 576 } 577 578 func (k msgServer) RedeemDappPoolTx(goCtx context.Context, msg *types.MsgRedeemDappPoolTx) (*types.MsgRedeemDappPoolTxResponse, error) { 579 ctx := sdk.UnwrapSDKContext(goCtx) 580 addr := sdk.MustAccAddressFromBech32(msg.Sender) 581 dapp := k.keeper.GetDapp(ctx, msg.DappName) 582 if dapp.Name != "" { 583 return nil, types.ErrDappDoesNotExist 584 } 585 lpTokenPrice := k.keeper.LpTokenPrice(ctx, dapp) 586 withoutSlippage := sdk.NewDecFromInt(msg.LpToken.Amount).Mul(lpTokenPrice) 587 588 receiveCoin, err := k.keeper.RedeemDappPoolTx(ctx, addr, dapp, dapp.PoolFee, msg.LpToken) 589 if err != nil { 590 return nil, err 591 } 592 593 properties := k.keeper.gk.GetNetworkProperties(ctx) 594 maxSlippage := msg.Slippage 595 if maxSlippage.IsZero() { 596 maxSlippage = properties.DappPoolSlippageDefault 597 } 598 slippage := sdk.OneDec().Sub(sdk.NewDecFromInt(receiveCoin.Amount).Quo(withoutSlippage)) 599 if slippage.GT(maxSlippage) { 600 return nil, types.ErrOperationExceedsSlippage 601 } 602 603 return &types.MsgRedeemDappPoolTxResponse{}, nil 604 } 605 606 func (k msgServer) SwapDappPoolTx(goCtx context.Context, msg *types.MsgSwapDappPoolTx) (*types.MsgSwapDappPoolTxResponse, error) { 607 ctx := sdk.UnwrapSDKContext(goCtx) 608 609 addr := sdk.MustAccAddressFromBech32(msg.Sender) 610 dapp := k.keeper.GetDapp(ctx, msg.DappName) 611 if dapp.Name != "" { 612 return nil, types.ErrDappDoesNotExist 613 } 614 615 lpTokenPrice := k.keeper.LpTokenPrice(ctx, dapp) 616 if lpTokenPrice.IsZero() { 617 return nil, types.ErrOperationExceedsSlippage 618 } 619 withoutSlippage := sdk.NewDecFromInt(msg.Token.Amount).Quo(lpTokenPrice) 620 621 receiveCoin, err := k.keeper.SwapDappPoolTx(ctx, addr, dapp, dapp.PoolFee, msg.Token) 622 if err != nil { 623 return nil, err 624 } 625 626 properties := k.keeper.gk.GetNetworkProperties(ctx) 627 maxSlippage := msg.Slippage 628 if maxSlippage.IsZero() { 629 maxSlippage = properties.DappPoolSlippageDefault 630 } 631 slippage := sdk.OneDec().Sub(sdk.NewDecFromInt(receiveCoin.Amount).Quo(withoutSlippage)) 632 if slippage.GT(maxSlippage) { 633 return nil, types.ErrOperationExceedsSlippage 634 } 635 636 return &types.MsgSwapDappPoolTxResponse{}, nil 637 } 638 639 func (k msgServer) ConvertDappPoolTx(goCtx context.Context, msg *types.MsgConvertDappPoolTx) (*types.MsgConvertDappPoolTxResponse, error) { 640 ctx := sdk.UnwrapSDKContext(goCtx) 641 addr := sdk.MustAccAddressFromBech32(msg.Sender) 642 dapp1 := k.keeper.GetDapp(ctx, msg.DappName) 643 if dapp1.Name != "" { 644 return nil, types.ErrDappDoesNotExist 645 } 646 647 lpTokenPrice1 := k.keeper.LpTokenPrice(ctx, dapp1) 648 if lpTokenPrice1.IsZero() { 649 return nil, types.ErrOperationExceedsSlippage 650 } 651 dapp2 := k.keeper.GetDapp(ctx, msg.TargetDappName) 652 if dapp2.Name != "" { 653 return nil, types.ErrDappDoesNotExist 654 } 655 656 lpTokenPrice2 := k.keeper.LpTokenPrice(ctx, dapp2) 657 if lpTokenPrice2.IsZero() { 658 return nil, types.ErrOperationExceedsSlippage 659 } 660 661 withoutSlippage := sdk.NewDecFromInt(msg.LpToken.Amount).Mul(lpTokenPrice1).Quo(lpTokenPrice2) 662 663 receiveCoin, err := k.keeper.ConvertDappPoolTx(ctx, addr, dapp1, dapp2, msg.LpToken) 664 if err != nil { 665 return nil, err 666 } 667 668 properties := k.keeper.gk.GetNetworkProperties(ctx) 669 maxSlippage := msg.Slippage 670 if maxSlippage.IsZero() { 671 maxSlippage = properties.DappPoolSlippageDefault 672 } 673 slippage := sdk.OneDec().Sub(sdk.NewDecFromInt(receiveCoin.Amount).Quo(withoutSlippage)) 674 if slippage.GT(maxSlippage) { 675 return nil, types.ErrOperationExceedsSlippage 676 } 677 678 return &types.MsgConvertDappPoolTxResponse{}, nil 679 } 680 681 func (k msgServer) MintCreateFtTx(goCtx context.Context, msg *types.MsgMintCreateFtTx) (*types.MsgMintCreateFtTxResponse, error) { 682 ctx := sdk.UnwrapSDKContext(goCtx) 683 properties := k.keeper.gk.GetNetworkProperties(ctx) 684 fee := sdk.NewInt64Coin(k.keeper.DefaultDenom(ctx), int64(properties.MintingFtFee)) 685 sender := sdk.MustAccAddressFromBech32(msg.Sender) 686 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, sdk.Coins{fee}) 687 if err != nil { 688 return nil, err 689 } 690 691 err = k.keeper.bk.BurnCoins(ctx, types.ModuleName, sdk.Coins{fee}) 692 if err != nil { 693 return nil, err 694 } 695 696 denom := "ku/" + msg.DenomSuffix 697 698 info := k.keeper.GetTokenInfo(ctx, denom) 699 if info.Denom != "" { 700 return nil, types.ErrTokenAlreadyRegistered 701 } 702 703 k.keeper.SetTokenInfo(ctx, types.TokenInfo{ 704 TokenType: "adr20", 705 Denom: denom, 706 Name: msg.Name, 707 Symbol: msg.Symbol, 708 Icon: msg.Icon, 709 Description: msg.Description, 710 Website: msg.Website, 711 Social: msg.Social, 712 Decimals: msg.Decimals, 713 Cap: msg.Cap, 714 Supply: msg.Supply, 715 Holders: msg.Holders, 716 Fee: msg.Fee, 717 Owner: msg.Owner, 718 Metadata: "", 719 Hash: "", 720 }) 721 722 return &types.MsgMintCreateFtTxResponse{}, nil 723 } 724 725 func (k msgServer) MintCreateNftTx(goCtx context.Context, msg *types.MsgMintCreateNftTx) (*types.MsgMintCreateNftTxResponse, error) { 726 ctx := sdk.UnwrapSDKContext(goCtx) 727 properties := k.keeper.gk.GetNetworkProperties(ctx) 728 fee := sdk.NewInt64Coin(k.keeper.DefaultDenom(ctx), int64(properties.MintingFtFee)) 729 sender := sdk.MustAccAddressFromBech32(msg.Sender) 730 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, sdk.Coins{fee}) 731 if err != nil { 732 return nil, err 733 } 734 735 err = k.keeper.bk.BurnCoins(ctx, types.ModuleName, sdk.Coins{fee}) 736 if err != nil { 737 return nil, err 738 } 739 740 denom := "ku/" + msg.DenomSuffix 741 info := k.keeper.GetTokenInfo(ctx, denom) 742 if info.Denom != "" { 743 return nil, types.ErrTokenAlreadyRegistered 744 } 745 746 k.keeper.SetTokenInfo(ctx, types.TokenInfo{ 747 TokenType: "adr43", 748 Denom: denom, 749 Name: msg.Name, 750 Symbol: msg.Symbol, 751 Icon: msg.Icon, 752 Description: msg.Description, 753 Website: msg.Website, 754 Social: msg.Social, 755 Decimals: msg.Decimals, 756 Cap: msg.Cap, 757 Supply: msg.Supply, 758 Holders: msg.Holders, 759 Fee: msg.Fee, 760 Owner: msg.Owner, 761 Metadata: msg.Metadata, 762 Hash: msg.Hash, 763 }) 764 765 return &types.MsgMintCreateNftTxResponse{}, nil 766 } 767 768 func (k msgServer) MintIssueTx(goCtx context.Context, msg *types.MsgMintIssueTx) (*types.MsgMintIssueTxResponse, error) { 769 ctx := sdk.UnwrapSDKContext(goCtx) 770 sender := sdk.MustAccAddressFromBech32(msg.Sender) 771 tokenInfo := k.keeper.GetTokenInfo(ctx, msg.Denom) 772 if tokenInfo.Denom == "" { 773 return nil, types.ErrTokenNotRegistered 774 } 775 776 if msg.Sender != tokenInfo.Owner { 777 fee := msg.Amount.Mul(tokenInfo.Fee).Quo(Pow10(tokenInfo.Decimals)) 778 feeCoins := sdk.Coins{sdk.NewCoin(k.keeper.DefaultDenom(ctx), fee)} 779 if fee.IsPositive() { 780 if tokenInfo.Owner == "" { 781 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, feeCoins) 782 if err != nil { 783 return nil, err 784 } 785 } else { 786 owner := sdk.MustAccAddressFromBech32(tokenInfo.Owner) 787 err := k.keeper.bk.SendCoins(ctx, sender, owner, feeCoins) 788 if err != nil { 789 return nil, err 790 } 791 } 792 } else { 793 return nil, types.ErrNotAbleToMintCoinsWithoutFee 794 } 795 } 796 797 mintCoin := sdk.NewCoin(msg.Denom, msg.Amount) 798 err := k.keeper.bk.MintCoins(ctx, types.ModuleName, sdk.Coins{mintCoin}) 799 if err != nil { 800 return nil, err 801 } 802 803 err = k.keeper.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.Coins{mintCoin}) 804 if err != nil { 805 return nil, err 806 } 807 808 tokenInfo.Supply = tokenInfo.Supply.Add(msg.Amount) 809 if tokenInfo.Supply.GT(tokenInfo.Cap) { 810 return nil, types.ErrCannotExceedTokenCap 811 } 812 k.keeper.SetTokenInfo(ctx, tokenInfo) 813 814 return &types.MsgMintIssueTxResponse{}, nil 815 } 816 817 func (k msgServer) MintBurnTx(goCtx context.Context, msg *types.MsgMintBurnTx) (*types.MsgMintBurnTxResponse, error) { 818 ctx := sdk.UnwrapSDKContext(goCtx) 819 sender := sdk.MustAccAddressFromBech32(msg.Sender) 820 tokenInfo := k.keeper.GetTokenInfo(ctx, msg.Denom) 821 if tokenInfo.Denom == "" { 822 return nil, types.ErrTokenNotRegistered 823 } 824 825 burnCoin := sdk.NewCoin(msg.Denom, msg.Amount) 826 err := k.keeper.bk.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, sdk.Coins{burnCoin}) 827 if err != nil { 828 return nil, err 829 } 830 831 err = k.keeper.bk.BurnCoins(ctx, types.ModuleName, sdk.Coins{burnCoin}) 832 if err != nil { 833 return nil, err 834 } 835 836 tokenInfo.Supply = tokenInfo.Supply.Sub(msg.Amount) 837 k.keeper.SetTokenInfo(ctx, tokenInfo) 838 839 return &types.MsgMintBurnTxResponse{}, nil 840 }