github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/staking/handler_shares.go (about) 1 package staking 2 3 import ( 4 "time" 5 6 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 7 "github.com/fibonacci-chain/fbc/x/staking/keeper" 8 "github.com/fibonacci-chain/fbc/x/staking/types" 9 ) 10 11 func handleMsgBindProxy(ctx sdk.Context, msg types.MsgBindProxy, k keeper.Keeper) (*sdk.Result, error) { 12 delegator, found := k.GetDelegator(ctx, msg.DelAddr) 13 14 if !found || delegator.Tokens.IsZero() { 15 return types.ErrNoDelegationToAddShares(msg.DelAddr.String()).Result() 16 } 17 18 if !delegator.Shares.Equal(sdk.ZeroDec()) { 19 return types.ErrAlreadyAddedShares(delegator.DelegatorAddress.String()).Result() 20 } 21 22 // proxy must delegated 23 proxyDelegator, found := k.GetDelegator(ctx, msg.ProxyAddress) 24 if !found || proxyDelegator.Tokens.IsZero() { 25 return types.ErrProxyNotFound(msg.ProxyAddress.String()).Result() 26 } 27 28 // target delegator must reg as a proxy 29 if !proxyDelegator.IsProxy { 30 return types.ErrProxyNotFound(msg.ProxyAddress.String()).Result() 31 } 32 33 // double proxy is denied on fbchain 34 if delegator.IsProxy { 35 return types.ErrDoubleProxy(delegator.DelegatorAddress.String()).Result() 36 } 37 38 // same proxy, only update shares 39 if delegator.HasProxy() && delegator.ProxyAddress.Equals(proxyDelegator.DelegatorAddress) { 40 updateTokens := proxyDelegator.TotalDelegatedTokens.Add(proxyDelegator.Tokens) 41 if err := k.UpdateShares(ctx, proxyDelegator.DelegatorAddress, updateTokens); err != nil { 42 return types.ErrInvalidDelegation(proxyDelegator.DelegatorAddress.String()).Result() 43 } 44 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 45 } 46 47 // unbind from the original proxy 48 if len(delegator.ProxyAddress) != 0 { 49 if sdkErr := unbindProxy(ctx, delegator.DelegatorAddress, k); sdkErr != nil { 50 return nil, sdkErr 51 } 52 } 53 54 // bind proxy relationship 55 delegator.BindProxy(msg.ProxyAddress) 56 57 // update proxy's shares weight 58 proxyDelegator.TotalDelegatedTokens = proxyDelegator.TotalDelegatedTokens.Add(delegator.Tokens) 59 60 k.SetDelegator(ctx, delegator) 61 k.SetDelegator(ctx, proxyDelegator) 62 k.SetProxyBinding(ctx, proxyDelegator.DelegatorAddress, delegator.DelegatorAddress, false) 63 64 finalTokens := proxyDelegator.TotalDelegatedTokens.Add(proxyDelegator.Tokens) 65 66 if err := k.UpdateShares(ctx, proxyDelegator.DelegatorAddress, finalTokens); err != nil { 67 return types.ErrInvalidDelegation(proxyDelegator.DelegatorAddress.String()).Result() 68 } 69 70 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 71 } 72 73 func unbindProxy(ctx sdk.Context, delAddr sdk.AccAddress, k keeper.Keeper) error { 74 delegator, found := k.GetDelegator(ctx, delAddr) 75 if !found { 76 return types.ErrNoDelegationToAddShares(delAddr.String()) 77 } 78 79 proxyDelegator, found := k.GetDelegator(ctx, delegator.ProxyAddress) 80 if !found { 81 return types.ErrProxyNotFound(delAddr.String()) 82 } 83 84 // update proxy's shares weight 85 if k.UpdateProxy(ctx, delegator, delegator.Tokens.Mul(sdk.NewDec(-1))) != nil { 86 return types.ErrInvalidDelegation(delAddr.String()) 87 } 88 // unbind proxy relationship 89 delegator.UnbindProxy() 90 k.SetDelegator(ctx, delegator) 91 k.SetProxyBinding(ctx, proxyDelegator.DelegatorAddress, delegator.DelegatorAddress, true) 92 93 return nil 94 } 95 96 func handleMsgUnbindProxy(ctx sdk.Context, msg types.MsgUnbindProxy, k keeper.Keeper) (*sdk.Result, error) { 97 if sdkErr := unbindProxy(ctx, msg.DelAddr, k); sdkErr != nil { 98 return nil, sdkErr 99 } 100 101 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 102 } 103 104 func regProxy(ctx sdk.Context, proxyAddr sdk.AccAddress, k keeper.Keeper) (*sdk.Result, error) { 105 // check status 106 proxy, found := k.GetDelegator(ctx, proxyAddr) 107 if !found { 108 return types.ErrNoDelegationToAddShares(proxyAddr.String()).Result() 109 } 110 if proxy.IsProxy { 111 return types.ErrProxyAlreadyExist(proxyAddr.String()).Result() 112 } 113 if len(proxy.ProxyAddress) != 0 { 114 return types.ErrAlreadyBound(proxyAddr.String()).Result() 115 } 116 117 proxy.RegProxy(true) 118 k.SetDelegator(ctx, proxy) 119 120 if k.UpdateShares(ctx, proxy.DelegatorAddress, proxy.Tokens) != nil { 121 return types.ErrInvalidDelegation(proxy.DelegatorAddress.String()).Result() 122 } 123 124 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 125 126 } 127 128 func unregProxy(ctx sdk.Context, proxyAddr sdk.AccAddress, k keeper.Keeper) (*sdk.Result, error) { 129 // check status 130 proxy, found := k.GetDelegator(ctx, proxyAddr) 131 if !found { 132 return types.ErrProxyNotFound(proxyAddr.String()).Result() 133 } 134 135 if !proxy.IsProxy { 136 return types.ErrProxyNotFound(proxyAddr.String()).Result() 137 } 138 139 proxy.RegProxy(false) 140 // unreg action, we need to erase all proxy relationship 141 proxy.TotalDelegatedTokens = sdk.ZeroDec() 142 k.ClearProxy(ctx, proxy.DelegatorAddress) 143 k.SetDelegator(ctx, proxy) 144 145 if k.UpdateShares(ctx, proxy.DelegatorAddress, proxy.Tokens) != nil { 146 return types.ErrInvalidDelegation(proxy.DelegatorAddress.String()).Result() 147 } 148 149 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 150 151 } 152 153 func handleRegProxy(ctx sdk.Context, msg types.MsgRegProxy, k keeper.Keeper) (*sdk.Result, error) { 154 if msg.Reg { 155 return regProxy(ctx, msg.ProxyAddress, k) 156 } 157 158 return unregProxy(ctx, msg.ProxyAddress, k) 159 } 160 161 func handleMsgAddShares(ctx sdk.Context, msg types.MsgAddShares, k keeper.Keeper) (*sdk.Result, error) { 162 maxValsToAddShares := int(k.ParamsMaxValsToAddShares(ctx)) 163 if len(msg.ValAddrs) == 0 { 164 return nil, types.ErrEmptyValidators() 165 } else if len(msg.ValAddrs) > maxValsToAddShares { 166 return types.ErrExceedValidatorAddrs(maxValsToAddShares).Result() 167 } 168 169 // 0. check whether the delegator has delegation 170 delegator, found := k.GetDelegator(ctx, msg.DelAddr) 171 if !found || delegator.Tokens.IsZero() { 172 return types.ErrNoDelegationToAddShares(msg.DelAddr.String()).Result() 173 } 174 if delegator.HasProxy() { 175 return types.ErrAddSharesDuringProxy(delegator.DelegatorAddress.String(), 176 delegator.ProxyAddress.String()).Result() 177 } 178 179 // 1. get last validators which were added shares to and existing in the store 180 lastVals, lastShares := k.GetLastValsAddedSharesExisted(ctx, msg.DelAddr) 181 182 // 2. withdraw the shares last time 183 k.WithdrawLastShares(ctx, msg.DelAddr, lastVals, lastShares) 184 185 // 3. get validators to add shares this time (if the validator doesn't exist, return error) 186 vals, sdkErr := k.GetValidatorsToAddShares(ctx, msg.ValAddrs) 187 if sdkErr != nil { 188 return nil, sdkErr 189 } 190 if sdkErr = validateSharesAdding(vals); sdkErr != nil { 191 return nil, sdkErr 192 } 193 194 // 4. get the total amount of self token and delegated token 195 totalTokens := delegator.Tokens.Add(delegator.TotalDelegatedTokens) 196 197 // 4.1 increment validators period 198 delegatorValAddresses := getValsAddrs(vals) 199 k.BeforeDelegationCreated(ctx, msg.DelAddr, delegatorValAddresses) 200 201 // 5. add shares to the vals this time 202 shares, sdkErr := k.AddSharesToValidators(ctx, msg.DelAddr, vals, totalTokens) 203 if sdkErr != nil { 204 return nil, sdkErr 205 } 206 207 // 6. update the delegator entity for this time 208 delegator.ValidatorAddresses = delegatorValAddresses 209 delegator.Shares = shares 210 k.SetDelegator(ctx, delegator) 211 212 // 7. create new delegator starting info 213 k.AfterDelegationModified(ctx, msg.DelAddr, delegator.ValidatorAddresses) 214 215 ctx.EventManager().EmitEvent(buildEventForHandlerAddShares(delegator)) 216 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 217 } 218 219 // validateSharesAdding gives a quick validity of target validators before shares adding 220 func validateSharesAdding(vals types.Validators) error { 221 if len(vals) == 0 { 222 return types.ErrEmptyValidators() 223 } 224 225 if valAddr, ok := isDismissed(vals); ok { 226 return types.ErrAddSharesToDismission(valAddr.String()) 227 } 228 229 return nil 230 } 231 232 // isDismissed tells whether validator with zero-msd is among the shares adding targets and returns the first dismissed 233 // validator address 234 func isDismissed(vals types.Validators) (sdk.ValAddress, bool) { 235 valsLen := len(vals) 236 for i := 0; i < valsLen; i++ { 237 if vals[i].MinSelfDelegation.IsZero() { 238 return vals[i].OperatorAddress, true 239 } 240 } 241 242 return nil, false 243 } 244 245 // getValsAddrs gets validator addresses from a set of validator's entities 246 func getValsAddrs(vals types.Validators) []sdk.ValAddress { 247 lenVals := len(vals) 248 valAddrs := make([]sdk.ValAddress, lenVals) 249 for i := 0; i < lenVals; i++ { 250 valAddrs[i] = vals[i].OperatorAddress 251 } 252 return valAddrs 253 } 254 255 func buildEventForHandlerAddShares(delegator types.Delegator) sdk.Event { 256 lenAttributes := len(delegator.ValidatorAddresses) + 2 257 attributes := make([]sdk.Attribute, lenAttributes) 258 attributes[0] = sdk.NewAttribute(types.AttributeKeyDelegator, delegator.DelegatorAddress.String()) 259 attributes[1] = sdk.NewAttribute(types.AttributeKeyShares, delegator.Shares.String()) 260 for i := 2; i < lenAttributes; i++ { 261 attributes[i] = sdk.NewAttribute(types.AttributeKeyValidatorToAddShares, delegator.ValidatorAddresses[i-2].String()) 262 } 263 264 return sdk.NewEvent(types.EventTypeAddShares, attributes...) 265 } 266 267 func handleMsgDeposit(ctx sdk.Context, msg types.MsgDeposit, k keeper.Keeper) (*sdk.Result, error) { 268 if msg.Amount.Denom != k.BondDenom(ctx) { 269 return ErrBadDenom().Result() 270 } 271 272 err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount) 273 if err != nil { 274 return nil, err 275 } 276 277 ctx.EventManager().EmitEvents(sdk.Events{ 278 sdk.NewEvent( 279 types.EventTypeDelegate, 280 sdk.NewAttribute(types.AttributeKeyValidator, msg.DelegatorAddress.String()), 281 sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), 282 ), 283 }) 284 return &sdk.Result{Events: ctx.EventManager().Events()}, nil 285 } 286 287 func handleMsgWithdraw(ctx sdk.Context, msg types.MsgWithdraw, k keeper.Keeper) (*sdk.Result, error) { 288 if msg.Amount.Denom != k.BondDenom(ctx) { 289 return ErrBadDenom().Result() 290 } 291 292 completionTime, err := k.Withdraw(ctx, msg.DelegatorAddress, msg.Amount) 293 if err != nil { 294 return nil, err 295 } 296 297 ctx.EventManager().EmitEvents(sdk.Events{ 298 sdk.NewEvent( 299 types.EventTypeUnbond, 300 sdk.NewAttribute(sdk.AttributeKeySender, msg.DelegatorAddress.String()), 301 sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), 302 sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)), 303 ), 304 }) 305 completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) 306 return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil 307 } 308 309 func handleMsgDestroyValidator(ctx sdk.Context, msg types.MsgDestroyValidator, k keeper.Keeper) (*sdk.Result, error) { 310 valAddr := sdk.ValAddress(msg.DelAddr) 311 // 0.check to see if the validator which belongs to the delegator exists 312 validator, found := k.GetValidator(ctx, valAddr) 313 if !found { 314 return ErrNoValidatorFound(valAddr.String()).Result() 315 } 316 317 completionTime, sdkErr := k.WithdrawMinSelfDelegation(ctx, msg.DelAddr, validator) 318 if sdkErr != nil { 319 return nil, sdkErr 320 } 321 322 ctx.EventManager().EmitEvents(sdk.Events{ 323 sdk.NewEvent( 324 types.EventTypeUnbond, 325 sdk.NewAttribute(sdk.AttributeKeySender, msg.DelAddr.String()), 326 sdk.NewAttribute(sdk.AttributeKeyAmount, validator.GetMinSelfDelegation().String()), 327 sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.Format(time.RFC3339)), 328 ), 329 }) 330 331 completionTimeBytes := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) 332 return &sdk.Result{Data: completionTimeBytes, Events: ctx.EventManager().Events()}, nil 333 334 }