github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/farm/handler.go (about) 1 package farm 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "github.com/fibonacci-chain/fbc/x/common" 8 9 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 10 11 "github.com/fibonacci-chain/fbc/x/common/perf" 12 "github.com/fibonacci-chain/fbc/x/farm/keeper" 13 "github.com/fibonacci-chain/fbc/x/farm/types" 14 ) 15 16 var destroyPoolHandler func(ctx sdk.Context, k keeper.Keeper, msg types.MsgDestroyPool) (*sdk.Result, error) = handleMsgDestroyPool 17 18 // NewHandler creates an sdk.Handler for all the farm type messages 19 func NewHandler(k keeper.Keeper) sdk.Handler { 20 return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 21 ctx.SetEventManager(sdk.NewEventManager()) 22 var handlerFun func() (*sdk.Result, error) 23 var name string 24 switch msg := msg.(type) { 25 case types.MsgCreatePool: 26 name = "handleMsgCreatePool" 27 handlerFun = func() (*sdk.Result, error) { 28 return handleMsgCreatePool(ctx, k, msg) 29 } 30 case types.MsgDestroyPool: 31 name = "handleMsgDestroyPool" 32 handlerFun = func() (*sdk.Result, error) { 33 return destroyPoolHandler(ctx, k, msg) 34 } 35 case types.MsgProvide: 36 name = "handleMsgProvide" 37 handlerFun = func() (*sdk.Result, error) { 38 return handleMsgProvide(ctx, k, msg) 39 } 40 case types.MsgLock: 41 name = "handleMsgLock" 42 handlerFun = func() (*sdk.Result, error) { 43 return handleMsgLock(ctx, k, msg) 44 } 45 case types.MsgUnlock: 46 name = "handleMsgUnlock" 47 handlerFun = func() (*sdk.Result, error) { 48 return handleMsgUnlock(ctx, k, msg) 49 } 50 case types.MsgClaim: 51 name = "handleMsgClaim" 52 handlerFun = func() (*sdk.Result, error) { 53 return handleMsgClaim(ctx, k, msg) 54 } 55 default: 56 errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) 57 return types.ErrUnknownFarmMsgType(errMsg).Result() 58 } 59 60 seq := perf.GetPerf().OnDeliverTxEnter(ctx, types.ModuleName, name) 61 defer perf.GetPerf().OnDeliverTxExit(ctx, types.ModuleName, name, seq) 62 63 res, err := handlerFun() 64 common.SanityCheckHandler(res, err) 65 return res, err 66 } 67 } 68 69 func handleMsgProvide(ctx sdk.Context, k keeper.Keeper, msg types.MsgProvide) (*sdk.Result, error) { 70 // 0. Check if the start_height_to_yield is more than current height 71 if msg.StartHeightToYield <= ctx.BlockHeight() { 72 return types.ErrInvalidStartHeight().Result() 73 } 74 75 // 1.1 Check farm pool 76 pool, found := k.GetFarmPool(ctx, msg.PoolName) 77 if !found { 78 return types.ErrNoFarmPoolFound(msg.PoolName).Result() 79 } 80 81 // 1.2 Check owner 82 if !pool.Owner.Equals(msg.Address) { 83 return types.ErrInvalidPoolOwner(msg.Address.String(), msg.PoolName).Result() 84 } 85 86 // 1.3 Check if the provided coin denom is the same as the locked coin name 87 if len(pool.YieldedTokenInfos) != 1 { 88 panic(fmt.Sprintf("The YieldedTokenInfos length is %d, which should be 1 in current code version", 89 len(pool.YieldedTokenInfos))) 90 } 91 if pool.YieldedTokenInfos[0].RemainingAmount.Denom != msg.Amount.Denom { 92 return types.ErrInvalidDenom(pool.YieldedTokenInfos[0].RemainingAmount.Denom, msg.Amount.Denom).Result() 93 } 94 95 // 2.1 Calculate how many provided token & native token could be yielded in current period 96 updatedPool, yieldedTokens := k.CalculateAmountYieldedBetween(ctx, pool) 97 98 // 2.2 Check if remaining amount is already zero 99 remainingAmount := updatedPool.YieldedTokenInfos[0].RemainingAmount 100 if !remainingAmount.IsZero() { 101 return types.ErrRemainingAmountNotZero(remainingAmount.String()).Result() 102 } 103 104 // 3. Terminate pool current period 105 k.IncrementPoolPeriod(ctx, pool.Name, pool.TotalValueLocked, yieldedTokens) 106 107 // 4. Transfer coin to farm module account 108 if err := k.SupplyKeeper().SendCoinsFromAccountToModule( 109 ctx, msg.Address, YieldFarmingAccount, msg.Amount.ToCoins(), 110 ); err != nil { 111 return types.ErrSendCoinsFromAccountToModuleFailed(err.Error()).Result() 112 } 113 114 // 5. init a new yielded_token_info struct, then set it into store 115 updatedPool.YieldedTokenInfos[0] = types.NewYieldedTokenInfo( 116 msg.Amount, msg.StartHeightToYield, msg.AmountYieldedPerBlock, 117 ) 118 k.SetFarmPool(ctx, updatedPool) 119 120 ctx.EventManager().EmitEvent(sdk.NewEvent( 121 types.EventTypeProvide, 122 sdk.NewAttribute(types.AttributeKeyAddress, msg.Address.String()), 123 sdk.NewAttribute(types.AttributeKeyPool, msg.PoolName), 124 sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), 125 sdk.NewAttribute(types.AttributeKeyStartHeightToYield, strconv.FormatInt(msg.StartHeightToYield, 10)), 126 sdk.NewAttribute(types.AttributeKeyAmountYieldPerBlock, msg.AmountYieldedPerBlock.String()), 127 )) 128 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 129 } 130 131 func handleMsgClaim(ctx sdk.Context, k keeper.Keeper, msg types.MsgClaim) (*sdk.Result, error) { 132 // 1. Get the pool info 133 pool, poolFound := k.GetFarmPool(ctx, msg.PoolName) 134 if !poolFound { 135 return types.ErrNoFarmPoolFound(msg.PoolName).Result() 136 } 137 138 // 2. Calculate how many provided token & native token could be yielded in current period 139 updatedPool, yieldedTokens := k.CalculateAmountYieldedBetween(ctx, pool) 140 141 // 3. Withdraw rewards 142 rewards, err := k.WithdrawRewards(ctx, pool.Name, pool.TotalValueLocked, yieldedTokens, msg.Address) 143 if err != nil { 144 return nil, err 145 } 146 147 // 4. Update the lock_info data 148 k.UpdateLockInfo(ctx, msg.Address, pool.Name, sdk.ZeroDec()) 149 150 // 5. Update farm pool 151 if updatedPool.TotalAccumulatedRewards.IsAllLT(rewards) { 152 panic("should not happen") 153 } 154 updatedPool.TotalAccumulatedRewards = updatedPool.TotalAccumulatedRewards.Sub(rewards) 155 k.SetFarmPool(ctx, updatedPool) 156 157 // 6. notify backend 158 k.OnClaim(ctx, msg.Address, pool.Name, rewards) 159 160 ctx.EventManager().EmitEvent(sdk.NewEvent( 161 types.EventTypeClaim, 162 sdk.NewAttribute(types.AttributeKeyAddress, msg.Address.String()), 163 sdk.NewAttribute(types.AttributeKeyPool, msg.PoolName), 164 )) 165 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 166 }