github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/staking/keeper/delegation.go (about) 1 package keeper 2 3 import ( 4 "bytes" 5 "fmt" 6 "time" 7 8 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 9 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 10 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/types" 11 ) 12 13 // return a specific delegation 14 func (k Keeper) GetDelegation(ctx sdk.Context, 15 delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( 16 delegation types.Delegation, found bool) { 17 18 store := ctx.KVStore(k.storeKey) 19 key := types.GetDelegationKey(delAddr, valAddr) 20 value := store.Get(key) 21 if value == nil { 22 return delegation, false 23 } 24 25 delegation = types.MustUnmarshalDelegation(k.cdc, value) 26 return delegation, true 27 } 28 29 // IterateAllDelegations iterate through all of the delegations 30 func (k Keeper) IterateAllDelegations(ctx sdk.Context, cb func(delegation types.Delegation) (stop bool)) { 31 store := ctx.KVStore(k.storeKey) 32 iterator := sdk.KVStorePrefixIterator(store, types.DelegationKey) 33 defer iterator.Close() 34 35 for ; iterator.Valid(); iterator.Next() { 36 delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) 37 if cb(delegation) { 38 break 39 } 40 } 41 } 42 43 // GetAllDelegations returns all delegations used during genesis dump 44 func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegation) { 45 k.IterateAllDelegations(ctx, func(delegation types.Delegation) bool { 46 delegations = append(delegations, delegation) 47 return false 48 }) 49 return delegations 50 } 51 52 // return all delegations to a specific validator. Useful for querier. 53 func (k Keeper) GetValidatorDelegations(ctx sdk.Context, valAddr sdk.ValAddress) (delegations []types.Delegation) { //nolint:interfacer 54 store := ctx.KVStore(k.storeKey) 55 iterator := sdk.KVStorePrefixIterator(store, types.DelegationKey) 56 defer iterator.Close() 57 58 for ; iterator.Valid(); iterator.Next() { 59 delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) 60 if delegation.GetValidatorAddr().Equals(valAddr) { 61 delegations = append(delegations, delegation) 62 } 63 } 64 return delegations 65 } 66 67 // return a given amount of all the delegations from a delegator 68 func (k Keeper) GetDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress, 69 maxRetrieve uint16) (delegations []types.Delegation) { 70 71 delegations = make([]types.Delegation, maxRetrieve) 72 73 store := ctx.KVStore(k.storeKey) 74 delegatorPrefixKey := types.GetDelegationsKey(delegator) 75 iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) 76 defer iterator.Close() 77 78 i := 0 79 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { 80 delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) 81 delegations[i] = delegation 82 i++ 83 } 84 return delegations[:i] // trim if the array length < maxRetrieve 85 } 86 87 // set a delegation 88 func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { 89 store := ctx.KVStore(k.storeKey) 90 b := types.MustMarshalDelegation(k.cdc, delegation) 91 store.Set(types.GetDelegationKey(delegation.DelegatorAddress, delegation.ValidatorAddress), b) 92 } 93 94 // remove a delegation 95 func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { 96 // TODO: Consider calling hooks outside of the store wrapper functions, it's unobvious. 97 k.BeforeDelegationRemoved(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress) 98 store := ctx.KVStore(k.storeKey) 99 store.Delete(types.GetDelegationKey(delegation.DelegatorAddress, delegation.ValidatorAddress)) 100 } 101 102 // return a given amount of all the delegator unbonding-delegations 103 func (k Keeper) GetUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAddress, 104 maxRetrieve uint16) (unbondingDelegations []types.UnbondingDelegation) { 105 106 unbondingDelegations = make([]types.UnbondingDelegation, maxRetrieve) 107 108 store := ctx.KVStore(k.storeKey) 109 delegatorPrefixKey := types.GetUBDsKey(delegator) 110 iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) 111 defer iterator.Close() 112 113 i := 0 114 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { 115 unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Value()) 116 unbondingDelegations[i] = unbondingDelegation 117 i++ 118 } 119 return unbondingDelegations[:i] // trim if the array length < maxRetrieve 120 } 121 122 // return a unbonding delegation 123 func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, 124 delAddr sdk.AccAddress, valAddr sdk.ValAddress) (ubd types.UnbondingDelegation, found bool) { 125 126 store := ctx.KVStore(k.storeKey) 127 key := types.GetUBDKey(delAddr, valAddr) 128 value := store.Get(key) 129 if value == nil { 130 return ubd, false 131 } 132 133 ubd = types.MustUnmarshalUBD(k.cdc, value) 134 return ubd, true 135 } 136 137 // return all unbonding delegations from a particular validator 138 func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []types.UnbondingDelegation) { 139 store := ctx.KVStore(k.storeKey) 140 iterator := sdk.KVStorePrefixIterator(store, types.GetUBDsByValIndexKey(valAddr)) 141 defer iterator.Close() 142 143 for ; iterator.Valid(); iterator.Next() { 144 key := types.GetUBDKeyFromValIndexKey(iterator.Key()) 145 value := store.Get(key) 146 ubd := types.MustUnmarshalUBD(k.cdc, value) 147 ubds = append(ubds, ubd) 148 } 149 return ubds 150 } 151 152 // iterate through all of the unbonding delegations 153 func (k Keeper) IterateUnbondingDelegations(ctx sdk.Context, fn func(index int64, ubd types.UnbondingDelegation) (stop bool)) { 154 store := ctx.KVStore(k.storeKey) 155 iterator := sdk.KVStorePrefixIterator(store, types.UnbondingDelegationKey) 156 defer iterator.Close() 157 158 for i := int64(0); iterator.Valid(); iterator.Next() { 159 ubd := types.MustUnmarshalUBD(k.cdc, iterator.Value()) 160 if stop := fn(i, ubd); stop { 161 break 162 } 163 i++ 164 } 165 } 166 167 // HasMaxUnbondingDelegationEntries - check if unbonding delegation has maximum number of entries 168 func (k Keeper) HasMaxUnbondingDelegationEntries(ctx sdk.Context, 169 delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) bool { 170 171 ubd, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) 172 if !found { 173 return false 174 } 175 return len(ubd.Entries) >= int(k.MaxEntries(ctx)) 176 } 177 178 // set the unbonding delegation and associated index 179 func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { 180 store := ctx.KVStore(k.storeKey) 181 bz := types.MustMarshalUBD(k.cdc, ubd) 182 key := types.GetUBDKey(ubd.DelegatorAddress, ubd.ValidatorAddress) 183 store.Set(key, bz) 184 store.Set(types.GetUBDByValIndexKey(ubd.DelegatorAddress, ubd.ValidatorAddress), []byte{}) // index, store empty bytes 185 } 186 187 // remove the unbonding delegation object and associated index 188 func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { 189 store := ctx.KVStore(k.storeKey) 190 key := types.GetUBDKey(ubd.DelegatorAddress, ubd.ValidatorAddress) 191 store.Delete(key) 192 store.Delete(types.GetUBDByValIndexKey(ubd.DelegatorAddress, ubd.ValidatorAddress)) 193 } 194 195 // SetUnbondingDelegationEntry adds an entry to the unbonding delegation at 196 // the given addresses. It creates the unbonding delegation if it does not exist 197 func (k Keeper) SetUnbondingDelegationEntry(ctx sdk.Context, 198 delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, 199 creationHeight int64, minTime time.Time, balance sdk.Int) types.UnbondingDelegation { 200 201 ubd, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) 202 if found { 203 ubd.AddEntry(creationHeight, minTime, balance) 204 } else { 205 ubd = types.NewUnbondingDelegation(delegatorAddr, validatorAddr, creationHeight, minTime, balance) 206 } 207 k.SetUnbondingDelegation(ctx, ubd) 208 return ubd 209 } 210 211 // unbonding delegation queue timeslice operations 212 213 // gets a specific unbonding queue timeslice. A timeslice is a slice of DVPairs 214 // corresponding to unbonding delegations that expire at a certain time. 215 func (k Keeper) GetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPairs []types.DVPair) { 216 store := ctx.KVStore(k.storeKey) 217 bz := store.Get(types.GetUnbondingDelegationTimeKey(timestamp)) 218 if bz == nil { 219 return []types.DVPair{} 220 } 221 k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &dvPairs) 222 return dvPairs 223 } 224 225 // Sets a specific unbonding queue timeslice. 226 func (k Keeper) SetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) { 227 store := ctx.KVStore(k.storeKey) 228 bz := k.cdc.MustMarshalBinaryLengthPrefixed(keys) 229 store.Set(types.GetUnbondingDelegationTimeKey(timestamp), bz) 230 } 231 232 // Insert an unbonding delegation to the appropriate timeslice in the unbonding queue 233 func (k Keeper) InsertUBDQueue(ctx sdk.Context, ubd types.UnbondingDelegation, 234 completionTime time.Time) { 235 236 timeSlice := k.GetUBDQueueTimeSlice(ctx, completionTime) 237 dvPair := types.DVPair{DelegatorAddress: ubd.DelegatorAddress, ValidatorAddress: ubd.ValidatorAddress} 238 if len(timeSlice) == 0 { 239 k.SetUBDQueueTimeSlice(ctx, completionTime, []types.DVPair{dvPair}) 240 } else { 241 timeSlice = append(timeSlice, dvPair) 242 k.SetUBDQueueTimeSlice(ctx, completionTime, timeSlice) 243 } 244 } 245 246 // Returns all the unbonding queue timeslices from time 0 until endTime 247 func (k Keeper) UBDQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { 248 store := ctx.KVStore(k.storeKey) 249 return store.Iterator(types.UnbondingQueueKey, 250 sdk.InclusiveEndBytes(types.GetUnbondingDelegationTimeKey(endTime))) 251 } 252 253 // Returns a concatenated list of all the timeslices inclusively previous to 254 // currTime, and deletes the timeslices from the queue 255 func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, 256 currTime time.Time) (matureUnbonds []types.DVPair) { 257 258 store := ctx.KVStore(k.storeKey) 259 // gets an iterator for all timeslices from time 0 until the current Blockheader time 260 unbondingTimesliceIterator := k.UBDQueueIterator(ctx, ctx.BlockHeader().Time) 261 defer unbondingTimesliceIterator.Close() 262 263 for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() { 264 timeslice := []types.DVPair{} 265 value := unbondingTimesliceIterator.Value() 266 k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) 267 matureUnbonds = append(matureUnbonds, timeslice...) 268 store.Delete(unbondingTimesliceIterator.Key()) 269 } 270 return matureUnbonds 271 } 272 273 // return a given amount of all the delegator redelegations 274 func (k Keeper) GetRedelegations(ctx sdk.Context, delegator sdk.AccAddress, 275 maxRetrieve uint16) (redelegations []types.Redelegation) { 276 redelegations = make([]types.Redelegation, maxRetrieve) 277 278 store := ctx.KVStore(k.storeKey) 279 delegatorPrefixKey := types.GetREDsKey(delegator) 280 iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) 281 defer iterator.Close() 282 283 i := 0 284 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { 285 redelegation := types.MustUnmarshalRED(k.cdc, iterator.Value()) 286 redelegations[i] = redelegation 287 i++ 288 } 289 return redelegations[:i] // trim if the array length < maxRetrieve 290 } 291 292 // return a redelegation 293 func (k Keeper) GetRedelegation(ctx sdk.Context, 294 delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (red types.Redelegation, found bool) { 295 296 store := ctx.KVStore(k.storeKey) 297 key := types.GetREDKey(delAddr, valSrcAddr, valDstAddr) 298 value := store.Get(key) 299 if value == nil { 300 return red, false 301 } 302 303 red = types.MustUnmarshalRED(k.cdc, value) 304 return red, true 305 } 306 307 // return all redelegations from a particular validator 308 func (k Keeper) GetRedelegationsFromSrcValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []types.Redelegation) { 309 store := ctx.KVStore(k.storeKey) 310 iterator := sdk.KVStorePrefixIterator(store, types.GetREDsFromValSrcIndexKey(valAddr)) 311 defer iterator.Close() 312 313 for ; iterator.Valid(); iterator.Next() { 314 key := types.GetREDKeyFromValSrcIndexKey(iterator.Key()) 315 value := store.Get(key) 316 red := types.MustUnmarshalRED(k.cdc, value) 317 reds = append(reds, red) 318 } 319 return reds 320 } 321 322 // check if validator is receiving a redelegation 323 func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, 324 delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) bool { 325 326 store := ctx.KVStore(k.storeKey) 327 prefix := types.GetREDsByDelToValDstIndexKey(delAddr, valDstAddr) 328 iterator := sdk.KVStorePrefixIterator(store, prefix) 329 defer iterator.Close() 330 331 return iterator.Valid() 332 } 333 334 // HasMaxRedelegationEntries - redelegation has maximum number of entries 335 func (k Keeper) HasMaxRedelegationEntries(ctx sdk.Context, 336 delegatorAddr sdk.AccAddress, validatorSrcAddr, 337 validatorDstAddr sdk.ValAddress) bool { 338 339 red, found := k.GetRedelegation(ctx, delegatorAddr, validatorSrcAddr, validatorDstAddr) 340 if !found { 341 return false 342 } 343 return len(red.Entries) >= int(k.MaxEntries(ctx)) 344 } 345 346 // set a redelegation and associated index 347 func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { 348 store := ctx.KVStore(k.storeKey) 349 bz := types.MustMarshalRED(k.cdc, red) 350 key := types.GetREDKey(red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress) 351 store.Set(key, bz) 352 store.Set(types.GetREDByValSrcIndexKey(red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress), []byte{}) 353 store.Set(types.GetREDByValDstIndexKey(red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress), []byte{}) 354 } 355 356 // SetUnbondingDelegationEntry adds an entry to the unbonding delegation at 357 // the given addresses. It creates the unbonding delegation if it does not exist 358 func (k Keeper) SetRedelegationEntry(ctx sdk.Context, 359 delegatorAddr sdk.AccAddress, validatorSrcAddr, 360 validatorDstAddr sdk.ValAddress, creationHeight int64, 361 minTime time.Time, balance sdk.Int, 362 sharesSrc, sharesDst sdk.Dec) types.Redelegation { 363 364 red, found := k.GetRedelegation(ctx, delegatorAddr, validatorSrcAddr, validatorDstAddr) 365 if found { 366 red.AddEntry(creationHeight, minTime, balance, sharesDst) 367 } else { 368 red = types.NewRedelegation(delegatorAddr, validatorSrcAddr, 369 validatorDstAddr, creationHeight, minTime, balance, sharesDst) 370 } 371 k.SetRedelegation(ctx, red) 372 return red 373 } 374 375 // iterate through all redelegations 376 func (k Keeper) IterateRedelegations(ctx sdk.Context, fn func(index int64, red types.Redelegation) (stop bool)) { 377 store := ctx.KVStore(k.storeKey) 378 iterator := sdk.KVStorePrefixIterator(store, types.RedelegationKey) 379 defer iterator.Close() 380 381 for i := int64(0); iterator.Valid(); iterator.Next() { 382 red := types.MustUnmarshalRED(k.cdc, iterator.Value()) 383 if stop := fn(i, red); stop { 384 break 385 } 386 i++ 387 } 388 } 389 390 // remove a redelegation object and associated index 391 func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { 392 store := ctx.KVStore(k.storeKey) 393 redKey := types.GetREDKey(red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress) 394 store.Delete(redKey) 395 store.Delete(types.GetREDByValSrcIndexKey(red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress)) 396 store.Delete(types.GetREDByValDstIndexKey(red.DelegatorAddress, red.ValidatorSrcAddress, red.ValidatorDstAddress)) 397 } 398 399 // redelegation queue timeslice operations 400 401 // Gets a specific redelegation queue timeslice. A timeslice is a slice of DVVTriplets corresponding to redelegations 402 // that expire at a certain time. 403 func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvvTriplets []types.DVVTriplet) { 404 store := ctx.KVStore(k.storeKey) 405 bz := store.Get(types.GetRedelegationTimeKey(timestamp)) 406 if bz == nil { 407 return []types.DVVTriplet{} 408 } 409 k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &dvvTriplets) 410 return dvvTriplets 411 } 412 413 // Sets a specific redelegation queue timeslice. 414 func (k Keeper) SetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVVTriplet) { 415 store := ctx.KVStore(k.storeKey) 416 bz := k.cdc.MustMarshalBinaryLengthPrefixed(keys) 417 store.Set(types.GetRedelegationTimeKey(timestamp), bz) 418 } 419 420 // Insert an redelegation delegation to the appropriate timeslice in the redelegation queue 421 func (k Keeper) InsertRedelegationQueue(ctx sdk.Context, red types.Redelegation, 422 completionTime time.Time) { 423 424 timeSlice := k.GetRedelegationQueueTimeSlice(ctx, completionTime) 425 dvvTriplet := types.DVVTriplet{ 426 DelegatorAddress: red.DelegatorAddress, 427 ValidatorSrcAddress: red.ValidatorSrcAddress, 428 ValidatorDstAddress: red.ValidatorDstAddress} 429 430 if len(timeSlice) == 0 { 431 k.SetRedelegationQueueTimeSlice(ctx, completionTime, []types.DVVTriplet{dvvTriplet}) 432 } else { 433 timeSlice = append(timeSlice, dvvTriplet) 434 k.SetRedelegationQueueTimeSlice(ctx, completionTime, timeSlice) 435 } 436 } 437 438 // Returns all the redelegation queue timeslices from time 0 until endTime 439 func (k Keeper) RedelegationQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { 440 store := ctx.KVStore(k.storeKey) 441 return store.Iterator(types.RedelegationQueueKey, sdk.InclusiveEndBytes(types.GetRedelegationTimeKey(endTime))) 442 } 443 444 // Returns a concatenated list of all the timeslices inclusively previous to 445 // currTime, and deletes the timeslices from the queue 446 func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time.Time) (matureRedelegations []types.DVVTriplet) { 447 store := ctx.KVStore(k.storeKey) 448 // gets an iterator for all timeslices from time 0 until the current Blockheader time 449 redelegationTimesliceIterator := k.RedelegationQueueIterator(ctx, ctx.BlockHeader().Time) 450 defer redelegationTimesliceIterator.Close() 451 452 for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() { 453 timeslice := []types.DVVTriplet{} 454 value := redelegationTimesliceIterator.Value() 455 k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) 456 matureRedelegations = append(matureRedelegations, timeslice...) 457 store.Delete(redelegationTimesliceIterator.Key()) 458 } 459 return matureRedelegations 460 } 461 462 // Perform a delegation, set/update everything necessary within the store. 463 // tokenSrc indicates the bond status of the incoming funds. 464 func (k Keeper) Delegate( 465 ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Dec, tokenSrc sdk.BondStatus, 466 validator types.Validator, subtractAccount bool, 467 ) (newShares sdk.Dec, err error) { 468 469 // In some situations, the exchange rate becomes invalid, e.g. if 470 // Validator loses all tokens due to slashing. In this case, 471 // make all future delegations invalid. 472 if validator.InvalidExRate() { 473 return sdk.ZeroDec(), types.ErrDelegatorShareExRateInvalid 474 } 475 476 // Get or create the delegation object 477 delegation, found := k.GetDelegation(ctx, delAddr, validator.OperatorAddress) 478 if !found { 479 delegation = types.NewDelegation(delAddr, validator.OperatorAddress, sdk.ZeroDec()) 480 } 481 482 // call the appropriate hook if present 483 if found { 484 k.BeforeDelegationSharesModified(ctx, delAddr, validator.OperatorAddress) 485 } else { 486 k.BeforeDelegationCreated(ctx, delAddr, validator.OperatorAddress) 487 } 488 489 // if subtractAccount is true then we are 490 // performing a delegation and not a redelegation, thus the source tokens are 491 // all non bonded 492 if subtractAccount { 493 if tokenSrc == sdk.Bonded { 494 panic("delegation token source cannot be bonded") 495 } 496 497 var sendName string 498 switch { 499 case validator.IsBonded(): 500 sendName = types.BondedPoolName 501 case validator.IsUnbonding(), validator.IsUnbonded(): 502 sendName = types.NotBondedPoolName 503 default: 504 panic("invalid validator status") 505 } 506 507 coins := sdk.NewCoins(sdk.NewCoin(k.BondDenom(ctx), bondAmt)) 508 err := k.supplyKeeper.DelegateCoinsFromAccountToModule(ctx, delegation.DelegatorAddress, sendName, coins) 509 if err != nil { 510 return sdk.Dec{}, err 511 } 512 } else { 513 514 // potentially transfer tokens between pools, if 515 switch { 516 case tokenSrc == sdk.Bonded && validator.IsBonded(): 517 // do nothing 518 case (tokenSrc == sdk.Unbonded || tokenSrc == sdk.Unbonding) && !validator.IsBonded(): 519 // do nothing 520 case (tokenSrc == sdk.Unbonded || tokenSrc == sdk.Unbonding) && validator.IsBonded(): 521 // transfer pools 522 k.notBondedTokensToBonded(ctx, bondAmt.RoundInt()) 523 case tokenSrc == sdk.Bonded && !validator.IsBonded(): 524 // transfer pools 525 k.bondedTokensToNotBonded(ctx, bondAmt.RoundInt()) 526 default: 527 panic("unknown token source bond status") 528 } 529 } 530 531 validator, newShares = k.AddValidatorTokensAndShares(ctx, validator, bondAmt.RoundInt()) 532 533 // Update delegation 534 delegation.Shares = delegation.Shares.Add(newShares) 535 k.SetDelegation(ctx, delegation) 536 537 // Call the after-modification hook 538 k.AfterDelegationModified(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress) 539 540 return newShares, nil 541 } 542 543 // unbond a particular delegation and perform associated store operations 544 func (k Keeper) unbond( 545 ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec, 546 ) (amount sdk.Int, err error) { 547 548 // check if a delegation object exists in the store 549 delegation, found := k.GetDelegation(ctx, delAddr, valAddr) 550 if !found { 551 return amount, types.ErrNoDelegatorForAddress 552 } 553 554 // call the before-delegation-modified hook 555 k.BeforeDelegationSharesModified(ctx, delAddr, valAddr) 556 557 // ensure that we have enough shares to remove 558 if delegation.Shares.LT(shares) { 559 return amount, sdkerrors.Wrap(types.ErrNotEnoughDelegationShares, delegation.Shares.String()) 560 } 561 562 // get validator 563 validator, found := k.GetValidator(ctx, valAddr) 564 if !found { 565 return amount, types.ErrNoValidatorFound 566 } 567 568 // subtract shares from delegation 569 delegation.Shares = delegation.Shares.Sub(shares) 570 571 isValidatorOperator := delegation.DelegatorAddress.Equals(validator.OperatorAddress) 572 573 // if the delegation is the operator of the validator and undelegating will decrease the validator's self delegation below their minimum 574 // trigger a jail validator 575 if isValidatorOperator && !validator.Jailed && 576 validator.TokensFromShares(delegation.Shares).TruncateInt().LT(validator.MinSelfDelegation) { 577 578 k.jailValidator(ctx, validator) 579 validator = k.mustGetValidator(ctx, validator.OperatorAddress) 580 } 581 582 // remove the delegation 583 if delegation.Shares.IsZero() { 584 k.RemoveDelegation(ctx, delegation) 585 } else { 586 k.SetDelegation(ctx, delegation) 587 // call the after delegation modification hook 588 k.AfterDelegationModified(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress) 589 } 590 591 // remove the shares and coins from the validator 592 // NOTE that the amount is later (in keeper.Delegation) moved between staking module pools 593 validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares) 594 595 if validator.DelegatorShares.IsZero() && validator.IsUnbonded() { 596 // if not unbonded, we must instead remove validator in EndBlocker once it finishes its unbonding period 597 k.RemoveValidator(ctx, validator.OperatorAddress) 598 } 599 600 return amount, nil 601 } 602 603 // getBeginInfo returns the completion time and height of a redelegation, along 604 // with a boolean signaling if the redelegation is complete based on the source 605 // validator. 606 func (k Keeper) getBeginInfo( 607 ctx sdk.Context, valSrcAddr sdk.ValAddress, 608 ) (completionTime time.Time, height int64, completeNow bool) { 609 610 validator, found := k.GetValidator(ctx, valSrcAddr) 611 612 // TODO: When would the validator not be found? 613 switch { 614 case !found || validator.IsBonded(): 615 616 // the longest wait - just unbonding period from now 617 completionTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx)) 618 height = ctx.BlockHeight() 619 return completionTime, height, false 620 621 case validator.IsUnbonded(): 622 return completionTime, height, true 623 624 case validator.IsUnbonding(): 625 return validator.UnbondingCompletionTime, validator.UnbondingHeight, false 626 627 default: 628 panic(fmt.Sprintf("unknown validator status: %s", validator.Status)) 629 } 630 } 631 632 // Undelegate unbonds an amount of delegator shares from a given validator. It 633 // will verify that the unbonding entries between the delegator and validator 634 // are not exceeded and unbond the staked tokens (based on shares) by creating 635 // an unbonding object and inserting it into the unbonding queue which will be 636 // processed during the staking EndBlocker. 637 func (k Keeper) Undelegate( 638 ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec, 639 ) (time.Time, error) { 640 641 validator, found := k.GetValidator(ctx, valAddr) 642 if !found { 643 return time.Time{}, types.ErrNoDelegatorForAddress 644 } 645 646 if k.HasMaxUnbondingDelegationEntries(ctx, delAddr, valAddr) { 647 return time.Time{}, types.ErrMaxUnbondingDelegationEntries 648 } 649 650 returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount) 651 if err != nil { 652 return time.Time{}, err 653 } 654 655 // transfer the validator tokens to the not bonded pool 656 if validator.IsBonded() { 657 k.bondedTokensToNotBonded(ctx, returnAmount) 658 } 659 660 completionTime := ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx)) 661 ubd := k.SetUnbondingDelegationEntry(ctx, delAddr, valAddr, ctx.BlockHeight(), completionTime, returnAmount) 662 k.InsertUBDQueue(ctx, ubd, completionTime) 663 664 return completionTime, nil 665 } 666 667 // CompleteUnbondingWithAmount completes the unbonding of all mature entries in 668 // the retrieved unbonding delegation object and returns the total unbonding 669 // balance or an error upon failure. 670 func (k Keeper) CompleteUnbondingWithAmount(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { 671 ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) 672 if !found { 673 return nil, types.ErrNoUnbondingDelegation 674 } 675 676 bondDenom := k.GetParams(ctx).BondDenom 677 balances := sdk.NewCoins() 678 ctxTime := ctx.BlockHeader().Time 679 680 // loop through all the entries and complete unbonding mature entries 681 for i := 0; i < len(ubd.Entries); i++ { 682 entry := ubd.Entries[i] 683 if entry.IsMature(ctxTime) { 684 ubd.RemoveEntry(int64(i)) 685 i-- 686 687 // track undelegation only when remaining or truncated shares are non-zero 688 if !entry.Balance.IsZero() { 689 amt := sdk.NewCoin(bondDenom, entry.Balance) 690 err := k.supplyKeeper.UndelegateCoinsFromModuleToAccount( 691 ctx, types.NotBondedPoolName, ubd.DelegatorAddress, sdk.NewCoins(amt), 692 ) 693 if err != nil { 694 return nil, err 695 } 696 697 balances = balances.Add(amt) 698 } 699 } 700 } 701 702 // set the unbonding delegation or remove it if there are no more entries 703 if len(ubd.Entries) == 0 { 704 k.RemoveUnbondingDelegation(ctx, ubd) 705 } else { 706 k.SetUnbondingDelegation(ctx, ubd) 707 } 708 709 return balances, nil 710 } 711 712 // CompleteUnbonding performs the same logic as CompleteUnbondingWithAmount except 713 // it does not return the total unbonding amount. 714 func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { 715 _, err := k.CompleteUnbondingWithAmount(ctx, delAddr, valAddr) 716 return err 717 } 718 719 // begin unbonding / redelegation; create a redelegation record 720 func (k Keeper) BeginRedelegation( 721 ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec, 722 ) (completionTime time.Time, err error) { 723 724 if bytes.Equal(valSrcAddr, valDstAddr) { 725 return time.Time{}, types.ErrSelfRedelegation 726 } 727 728 dstValidator, found := k.GetValidator(ctx, valDstAddr) 729 if !found { 730 return time.Time{}, types.ErrBadRedelegationDst 731 } 732 733 srcValidator, found := k.GetValidator(ctx, valSrcAddr) 734 if !found { 735 return time.Time{}, types.ErrBadRedelegationDst 736 } 737 738 // check if this is a transitive redelegation 739 if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) { 740 return time.Time{}, types.ErrTransitiveRedelegation 741 } 742 743 if k.HasMaxRedelegationEntries(ctx, delAddr, valSrcAddr, valDstAddr) { 744 return time.Time{}, types.ErrMaxRedelegationEntries 745 } 746 747 returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount) 748 if err != nil { 749 return time.Time{}, err 750 } 751 752 if returnAmount.IsZero() { 753 return time.Time{}, types.ErrTinyRedelegationAmount 754 } 755 756 sharesCreated, err := k.Delegate(ctx, delAddr, returnAmount.ToDec(), srcValidator.GetStatus(), dstValidator, false) 757 if err != nil { 758 return time.Time{}, err 759 } 760 761 // create the unbonding delegation 762 completionTime, height, completeNow := k.getBeginInfo(ctx, valSrcAddr) 763 764 if completeNow { // no need to create the redelegation object 765 return completionTime, nil 766 } 767 768 red := k.SetRedelegationEntry( 769 ctx, delAddr, valSrcAddr, valDstAddr, 770 height, completionTime, returnAmount, sharesAmount, sharesCreated, 771 ) 772 k.InsertRedelegationQueue(ctx, red, completionTime) 773 return completionTime, nil 774 } 775 776 // CompleteRedelegationWithAmount completes the redelegations of all mature entries in the 777 // retrieved redelegation object and returns the total redelegation (initial) 778 // balance or an error upon failure. 779 func (k Keeper) CompleteRedelegationWithAmount( 780 ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, 781 ) (sdk.Coins, error) { 782 783 red, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr) 784 if !found { 785 return nil, types.ErrNoRedelegation 786 } 787 788 bondDenom := k.GetParams(ctx).BondDenom 789 balances := sdk.NewCoins() 790 ctxTime := ctx.BlockHeader().Time 791 792 // loop through all the entries and complete mature redelegation entries 793 for i := 0; i < len(red.Entries); i++ { 794 entry := red.Entries[i] 795 if entry.IsMature(ctxTime) { 796 red.RemoveEntry(int64(i)) 797 i-- 798 799 if !entry.InitialBalance.IsZero() { 800 balances = balances.Add(sdk.NewCoin(bondDenom, entry.InitialBalance)) 801 } 802 } 803 } 804 805 // set the redelegation or remove it if there are no more entries 806 if len(red.Entries) == 0 { 807 k.RemoveRedelegation(ctx, red) 808 } else { 809 k.SetRedelegation(ctx, red) 810 } 811 812 return balances, nil 813 } 814 815 // CompleteRedelegation performs the same logic as CompleteRedelegationWithAmount 816 // except it does not return the total redelegation amount. 817 func (k Keeper) CompleteRedelegation( 818 ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, 819 ) error { 820 821 _, err := k.CompleteRedelegationWithAmount(ctx, delAddr, valSrcAddr, valDstAddr) 822 return err 823 } 824 825 // ValidateUnbondAmount validates that a given unbond or redelegation amount is 826 // valied based on upon the converted shares. If the amount is valid, the total 827 // amount of respective shares is returned, otherwise an error is returned. 828 func (k Keeper) ValidateUnbondAmount( 829 ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Dec, 830 ) (shares sdk.Dec, err error) { 831 832 validator, found := k.GetValidator(ctx, valAddr) 833 if !found { 834 return shares, types.ErrNoValidatorFound 835 } 836 837 del, found := k.GetDelegation(ctx, delAddr, valAddr) 838 if !found { 839 return shares, types.ErrNoDelegation 840 } 841 842 shares, err = validator.SharesFromTokens(amt.RoundInt()) 843 if err != nil { 844 return shares, err 845 } 846 847 sharesTruncated, err := validator.SharesFromTokensTruncated(amt.RoundInt()) 848 if err != nil { 849 return shares, err 850 } 851 852 delShares := del.GetShares() 853 if sharesTruncated.GT(delShares) { 854 return shares, types.ErrBadSharesAmount 855 } 856 857 // Cap the shares at the delegation's shares. Shares being greater could occur 858 // due to rounding, however we don't want to truncate the shares or take the 859 // minimum because we want to allow for the full withdraw of shares from a 860 // delegation. 861 if shares.GT(delShares) { 862 shares = delShares 863 } 864 865 return shares, nil 866 }