diff --git a/x/distribution/client/cli/tx.go b/x/distribution/client/cli/tx.go new file mode 100644 index 000000000000..771572074d87 --- /dev/null +++ b/x/distribution/client/cli/tx.go @@ -0,0 +1,76 @@ +// nolint +package cli + +import ( + "os" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/utils" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/spf13/cobra" + "github.com/spf13/viper" + wire "github.com/tendermint/go-wire" +) + +type TxWithdrawDelegationRewardsAll struct { + delegatorAddr sdk.AccAddress + withdrawAddr sdk.AccAddress // address to make the withdrawal to +} + +type TxWithdrawDelegationReward struct { + delegatorAddr sdk.AccAddress + validatorAddr sdk.AccAddress + withdrawAddr sdk.AccAddress // address to make the withdrawal to +} + +type TxWithdrawValidatorRewardsAll struct { + operatorAddr sdk.AccAddress // validator address to withdraw from + withdrawAddr sdk.AccAddress // address to make the withdrawal to +} + +var ( + flagOnlyFromValidator = "only-from-validator" + flagIsValidator = "is-validator" +) + +// GetCmdDelegate implements the delegate command. +func GetCmdWithdrawDelegationRewardsAll(cdc *wire.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw-rewards [delegator]", + Short: "withdraw rewards from delegation accounts", + RunE: func(cmd *cobra.Command, args []string) error { + txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc) + cliCtx := context.NewCLIContext(). + WithCodec(cdc). + WithLogger(os.Stdout). + WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) + + amount, err := sdk.ParseCoin(viper.GetString(FlagAmount)) + if err != nil { + return err + } + + delAddr, err := cliCtx.GetFromAddress() + if err != nil { + return err + } + + valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) + if err != nil { + return err + } + + msg := stake.NewMsgDelegate(delAddr, valAddr, amount) + + // build and sign the transaction, then broadcast to Tendermint + return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) + }, + } + + // TODO add flags for "is-validator", "only-for-validator" + cmd.Flags().String(flagOnlyFromValidator, "", "Only withdraw from this validator address") + cmd.Flags().Bool(flagIsValidator, false, "Also withdraw validator's commission") + + return cmd +} diff --git a/x/distribution/handler.go b/x/distribution/handler.go index bd317b9c1434..39371610f4f9 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -1,144 +1,14 @@ package stake import ( - "time" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/stake/keeper" ) -// burn burn burn -func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} - -// Called every block, process inflation, update validator set -func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Validator) { - pool := k.GetPool(ctx) - - // Process provision inflation - blockTime := ctx.BlockHeader().Time - if blockTime.Sub(pool.InflationLastTime) >= time.Hour { - params := k.GetParams(ctx) - pool.InflationLastTime = blockTime - pool = pool.ProcessProvisions(params) - k.SetPool(ctx, pool) - } - - // reset the intra-transaction counter - k.SetIntraTxCounter(ctx, 0) - - // calculate validator set changes - ValidatorUpdates = k.GetTendermintUpdates(ctx) - k.ClearTendermintUpdates(ctx) - return -} - -/* -func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution, - sumPowerPrecommitValidators, totalBondedTokens, communityTax, - proposerCommissionRate sdk.Dec) - - feesCollectedDec = MakeDecCoins(feesCollected) - proposerReward = feesCollectedDec * (0.01 + 0.04 - * sumPowerPrecommitValidators / totalBondedTokens) - - commission = proposerReward * proposerCommissionRate - proposer.PoolCommission += commission - proposer.Pool += proposerReward - commission - - communityFunding = feesCollectedDec * communityTax - global.CommunityFund += communityFunding - - poolReceived = feesCollectedDec - proposerReward - communityFunding - global.Pool += poolReceived - global.EverReceivedPool += poolReceived - global.LastReceivedPool = poolReceived - - SetValidatorDistribution(proposer) - SetGlobal(global) - -///////////////////////////////////////////////////////////////////////////////////////////////////////// - -type TxWithdrawDelegationRewardsAll struct { - delegatorAddr sdk.AccAddress - withdrawAddr sdk.AccAddress // address to make the withdrawal to -} - -func WithdrawDelegationRewardsAll(delegatorAddr, withdrawAddr sdk.AccAddress) - height = GetHeight() - withdraw = GetDelegatorRewardsAll(delegatorAddr, height) - AddCoins(withdrawAddr, withdraw.TruncateDecimal()) - -func GetDelegatorRewardsAll(delegatorAddr sdk.AccAddress, height int64) DecCoins +// distribution fee handler +func DistributionFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) { - // get all distribution scenarios - delegations = GetDelegations(delegatorAddr) - - // collect all entitled rewards - withdraw = 0 - pool = stake.GetPool() - global = GetGlobal() - for delegation = range delegations - delInfo = GetDelegationDistInfo(delegation.DelegatorAddr, - delegation.ValidatorAddr) - valInfo = GetValidatorDistInfo(delegation.ValidatorAddr) - validator = GetValidator(delegation.ValidatorAddr) - - global, diWithdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens, - validator.Tokens, validator.DelegatorShares, validator.Commission) - withdraw += diWithdraw - - SetGlobal(global) - return withdraw - -///////////////////////////////////////////////////////////////////////////////////////////////////////// - -type TxWithdrawDelegationReward struct { - delegatorAddr sdk.AccAddress - validatorAddr sdk.AccAddress - withdrawAddr sdk.AccAddress // address to make the withdrawal to } -func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress) - height = GetHeight() - - // get all distribution scenarios - pool = stake.GetPool() - global = GetGlobal() - delInfo = GetDelegationDistInfo(delegatorAddr, - validatorAddr) - valInfo = GetValidatorDistInfo(validatorAddr) - validator = GetValidator(validatorAddr) - - global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens, - validator.Tokens, validator.DelegatorShares, validator.Commission) - - SetGlobal(global) - AddCoins(withdrawAddr, withdraw.TruncateDecimal()) - -///////////////////////////////////////////////////////////////////////////////////////////////////////// - -type TxWithdrawValidatorRewardsAll struct { - operatorAddr sdk.AccAddress // validator address to withdraw from - withdrawAddr sdk.AccAddress // address to make the withdrawal to -} - -func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress) - - height = GetHeight() - global = GetGlobal() - pool = GetPool() - ValInfo = GetValidatorDistInfo(delegation.ValidatorAddr) - validator = GetValidator(delegation.ValidatorAddr) - - // withdraw self-delegation - withdraw = GetDelegatorRewardsAll(validator.OperatorAddr, height) - - // withdrawal validator commission rewards - global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens, - validator.Tokens, validator.Commission) - withdraw += commission - SetGlobal(global) - - AddCoins(withdrawAddr, withdraw.TruncateDecimal()) - -*/ +////////////////////////////////////////////////////////////////////////////////// +// burn burn burn +func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {} diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go new file mode 100644 index 000000000000..ce111b559c87 --- /dev/null +++ b/x/distribution/keeper/allocation.go @@ -0,0 +1,27 @@ +package keeper + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// XXX TODO +func AllocateFees(feesCollected sdk.Coins, feePool FeePool, proposer ValidatorDistribution, + sumPowerPrecommitValidators, totalBondedTokens, communityTax, + proposerCommissionRate sdk.Dec) { + + feesCollectedDec = MakeDecCoins(feesCollected) + proposerReward = feesCollectedDec * (0.01 + 0.04*sumPowerPrecommitValidators/totalBondedTokens) + + commission = proposerReward * proposerCommissionRate + proposer.PoolCommission += commission + proposer.Pool += proposerReward - commission + + communityFunding = feesCollectedDec * communityTax + feePool.CommunityFund += communityFunding + + poolReceived = feesCollectedDec - proposerReward - communityFunding + feePool.Pool += poolReceived + feePool.EverReceivedPool += poolReceived + feePool.LastReceivedPool = poolReceived + + SetValidatorDistribution(proposer) + SetFeePool(feePool) +} diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go new file mode 100644 index 000000000000..72e96715b3c5 --- /dev/null +++ b/x/distribution/keeper/delegation.go @@ -0,0 +1,84 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/stake" +) + +// get the delegator distribution info +func (k Keeper) GetDelegatorDistInfo(ctx sdk.Context, delAddr sdk.AccAddress, + valOperatorAddr sdk.ValAddress) (ddi types.DelegatorDistInfo) { + + store := ctx.KVStore(k.storeKey) + + b := store.Get(GetDelegationDistInfoKey(delAddr, valOperatorAddr)) + if b == nil { + panic("Stored delegation-distribution info should not have been nil") + } + + k.cdc.MustUnmarshalBinary(b, &ddi) + return +} + +// set the delegator distribution info +func (k Keeper) SetDelegatorDistInfo(ctx sdk.Context, ddi types.DelegatorDistInfo) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshalBinary(ddi) + store.Set(GetDelegationDistInfoKey(ddi.DelegatorAddr, ddi.ValOperatorAddr), b) +} + +//___________________________________________________________________________________________ + +// XXX TODO +func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress) { + height = ctx.BlockHeight() + + // get all distribution scenarios + pool = stake.GetPool() + feePool = GetFeePool() + delInfo = GetDelegationDistInfo(delegatorAddr, + validatorAddr) + valInfo = GetValidatorDistInfo(validatorAddr) + validator = GetValidator(validatorAddr) + + feePool, withdraw = delInfo.WithdrawRewards(feePool, valInfo, height, pool.BondedTokens, + validator.Tokens, validator.DelegatorShares, validator.Commission) + + SetFeePool(feePool) + AddCoins(withdrawAddr, withdraw.TruncateDecimal()) +} + +/////////////////////////////////////////////////////////////////////////////////////// + +// XXX TODO +func (k Keeper) WithdrawDelegationRewardsAll(ctx sdk.Context, delegatorAddr, withdrawAddr sdk.AccAddress) { + height = ctx.BlockHeight() + withdraw = GetDelegatorRewardsAll(delegatorAddr, height) + k.coinsKeeper.AddCoins(withdrawAddr, withdraw.Amount.TruncateDecimal()) +} + +// XXX TODO +func (k Keeper) GetDelegatorRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress, height int64) DecCoins { + + // collect all entitled rewards + withdraw = 0 + pool = stake.GetPool() + feePool = GetFeePool() + + // iterate over all the delegations + operationAtDelegation := func(_ int64, del types.Delegation) (stop bool) { + delInfo = GetDelegationDistInfo(delAddr, del.ValidatorAddr) + valInfo = GetValidatorDistInfo(del.ValidatorAddr) + validator = GetValidator(del.ValidatorAddr) + + feePool, diWithdraw = delInfo.WithdrawRewards(feePool, valInfo, height, pool.BondedTokens, + validator.Tokens, validator.DelegatorShares, validator.Commission) + withdraw += diWithdraw + return false + } + k.stakeKeeper.IterateDelegations(ctx, delAddr, operationAtDelegation) + + SetFeePool(feePool) + return withdraw +} diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index a5d6459ac5bc..c0bf48cea530 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -2,9 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/stake" wire "github.com/tendermint/go-wire" ) @@ -12,15 +10,15 @@ import ( type Keeper struct { storeKey sdk.StoreKey cdc *wire.Codec - coinKeeper bank.Keeper - stakeKeeper stake.Keeper + coinKeeper types.CoinKeeper + stakeKeeper types.StakeKeeper // codespace codespace sdk.CodespaceType } -func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, - sk stake.Keeper, codespace sdk.CodespaceType) Keeper { +func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck types.CoinKeeper, + sk types.StakeKeeper, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ storeKey: key, @@ -33,70 +31,22 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, //______________________________________________________________________ -// get the global distribution info -func (k Keeper) GetGlobal(ctx sdk.Context) (global types.Global) { +// get the global fee pool distribution info +func (k Keeper) GetFeePool(ctx sdk.Context) (feePool types.Global) { store := ctx.KVStore(k.storeKey) b := store.Get(GlobalKey) if b == nil { - panic("Stored global should not have been nil") + panic("Stored fee pool should not have been nil") } - k.cdc.MustUnmarshalBinary(b, &global) + k.cdc.MustUnmarshalBinary(b, &feePool) return } -// set the global distribution info -func (k Keeper) SetGlobal(ctx sdk.Context, global types.Global) { +// set the global fee pool distribution info +func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.Global) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(global) + b := k.cdc.MustMarshalBinary(feePool) store.Set(GlobalKey, b) } - -//______________________________________________________________________ - -// get the delegator distribution info -func (k Keeper) GetDelegatorDistInfo(ctx sdk.Context, delAddr sdk.AccAddress, - valOperatorAddr sdk.ValAddress) (ddi types.DelegatorDistInfo) { - - store := ctx.KVStore(k.storeKey) - - b := store.Get(GetDelegationDistInfoKey(delAddr, valOperatorAddr)) - if b == nil { - panic("Stored delegation-distribution info should not have been nil") - } - - k.cdc.MustUnmarshalBinary(b, &ddi) - return -} - -// set the delegator distribution info -func (k Keeper) SetDelegatorDistInfo(ctx sdk.Context, ddi types.DelegatorDistInfo) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(ddi) - store.Set(GetDelegationDistInfoKey(ddi.DelegatorAddr, ddi.ValOperatorAddr), b) -} - -//______________________________________________________________________ - -// get the validator distribution info -func (k Keeper) GetValidatorDistInfo(ctx sdk.Context, - operatorAddr sdk.ValAddress) (vdi types.ValidatorDistInfo) { - - store := ctx.KVStore(k.storeKey) - - b := store.Get(GetValidatorDistInfoKey(operatorAddr)) - if b == nil { - panic("Stored delegation-distribution info should not have been nil") - } - - k.cdc.MustUnmarshalBinary(b, &vdi) - return -} - -// set the validator distribution info -func (k Keeper) SetValidatorDistInfo(ctx sdk.Context, vdi types.ValidatorDistInfo) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(vdi) - store.Set(GetValidatorDistInfoKey(vdi.OperatorAddr), b) -} diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go deleted file mode 100644 index 75200d755d71..000000000000 --- a/x/distribution/keeper/keeper_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package keeper - -// XXX TODO diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go new file mode 100644 index 000000000000..9a057b85b940 --- /dev/null +++ b/x/distribution/keeper/validator.go @@ -0,0 +1,48 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +// get the validator distribution info +func (k Keeper) GetValidatorDistInfo(ctx sdk.Context, + operatorAddr sdk.ValAddress) (vdi types.ValidatorDistInfo) { + + store := ctx.KVStore(k.storeKey) + + b := store.Get(GetValidatorDistInfoKey(operatorAddr)) + if b == nil { + panic("Stored delegation-distribution info should not have been nil") + } + + k.cdc.MustUnmarshalBinary(b, &vdi) + return +} + +// set the validator distribution info +func (k Keeper) SetValidatorDistInfo(ctx sdk.Context, vdi types.ValidatorDistInfo) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshalBinary(vdi) + store.Set(GetValidatorDistInfoKey(vdi.OperatorAddr), b) +} + +// XXX TODO +func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, operatorAddr, withdrawAddr sdk.AccAddress) { + height = ctx.BlockHeight() + feePool = k.GetFeePool(ctx) + pool = k.stakeKeeper.GetPool(ctx) + ValInfo = k.GetValidatorDistInfo(delegation.ValidatorAddr) + validator = k.GetValidator(delegation.ValidatorAddr) + + // withdraw self-delegation + withdraw = k.GetDelegatorRewardsAll(validator.OperatorAddr, height) + + // withdrawal validator commission rewards + feePool, commission = valInfo.WithdrawCommission(feePool, valInfo, height, pool.BondedTokens, + validator.Tokens, validator.Commission) + withdraw += commission + SetFeePool(feePool) + + k.coinKeeper.AddCoins(withdrawAddr, withdraw.TruncateDecimal()) +} diff --git a/x/distribution/types/fee_pool.go b/x/distribution/types/fee_pool.go new file mode 100644 index 000000000000..23e1584884ab --- /dev/null +++ b/x/distribution/types/fee_pool.go @@ -0,0 +1,41 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// coins with decimal +type DecCoins []DecCoin + +// Coins which can have additional decimal points +type DecCoin struct { + Amount sdk.Dec `json:"amount"` + Denom string `json:"denom"` +} + +// total accumulation tracker +type TotalAccum struct { + UpdateHeight int64 `json:"update_height"` + Accum sdk.Dec `json:"accum"` +} + +// update total validator accumulation factor +func (ta TotalAccum) Update(height int64, accumCreatedPerBlock sdk.Dec) TotalAccum { + blocks := height - ta.UpdateHeight + f.Accum += accumCreatedPerBlock.Mul(sdk.NewDec(blocks)) + ta.UpdateHeight = height + return ta +} + +//___________________________________________________________________________________________ + +// global fee pool for distribution +type FeePool struct { + ValAccum TotalAccum `json:"val_accum"` // total valdator accum held by validators + Pool DecCoins `json:"pool"` // funds for all validators which have yet to be withdrawn + CommunityPool DecCoins `json:"community_pool"` // pool for community funds yet to be spent} +} + +// update total validator accumulation factor +func (f FeePool) UpdateTotalValAccum(height int64, totalBondedTokens Dec) FeePool { + f.ValAccum = f.ValAccum.Update(height, totalBondedTokens) + return f +} diff --git a/x/distribution/types/global.go b/x/distribution/types/global.go deleted file mode 100644 index b3b3e2d60f03..000000000000 --- a/x/distribution/types/global.go +++ /dev/null @@ -1,30 +0,0 @@ -package types - -import sdk "github.com/cosmos/cosmos-sdk/types" - -// coins with decimal -type DecCoins []DecCoin - -// Coins which can have additional decimal points -type DecCoin struct { - Amount sdk.Dec - Denom string -} - -//___________________________________________________________________________________________ - -// Global state for distribution -type Global struct { - TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated - TotalValAccum sdk.Dec // total valdator accum held by validators - Pool DecCoins // funds for all validators which have yet to be withdrawn - CommunityPool DecCoins // pool for community funds yet to be spent -} - -// update total validator accumulation factor -func (g Global) UpdateTotalValAccum(height int64, totalbondedtokens dec) Global { - blocks := height - g.totalvalaccumupdateheight - g.totalvalaccum += totaldelshares * blocks - g.totalvalaccumupdateheight = height - return g -} diff --git a/x/distribution/types/keepers.go b/x/distribution/types/keepers.go new file mode 100644 index 000000000000..15a137718558 --- /dev/null +++ b/x/distribution/types/keepers.go @@ -0,0 +1,17 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// expected stake keeper +type StakeKeeper interface { + IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, + fn func(index int64, del types.Delegation) (stop bool)) + GetDelegation(ctx sdk.Context, delAddr sdk.AccAddress) + GetValidator(ctx sdk.Context, valAddr sdk.AccAddress) + GetPool(ctx sdk.Context) +} + +// expected coin keeper +type CoinKeeper interface { + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) +} diff --git a/x/distribution/types/validator_info.go b/x/distribution/types/validator_info.go index 8ca532d86f10..4a1b1f86d0ec 100644 --- a/x/distribution/types/validator_info.go +++ b/x/distribution/types/validator_info.go @@ -10,15 +10,12 @@ type ValidatorDistInfo struct { Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward) PoolCommission DecCoins // commission collected by this validator (pending withdrawal) - TotalDelAccumUpdateHeight int64 // last height which the total delegator accum was updated - TotalDelAccum sdk.Dec // total proposer pool accumulation factor held by delegators + DelAccum TotalAccum `json:"dek_accum"` // total proposer pool accumulation factor held by delegators } // update total delegator accumululation func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo { - blocks = height - vi.TotalDelAccumUpdateHeight - vi.TotalDelAccum += totalDelShares * blocks - vi.TotalDelAccumUpdateHeight = height + vi.DelAccum = vi.DelAccum.Update(height, totalDelShares) return vi } diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 9a596ffbce5e..e4ec199efd29 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -64,6 +64,24 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.AccAddress, return delegations[:i] // trim } +// iterate through all of the delegations from a delegator +func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, + fn func(index int64, del types.Delegation) (stop bool)) { + + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := GetDelegationsKey(delAddr) + iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest + for i := int64(0); iterator.Valid(); iterator.Next() { + del := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + stop := fn(i, del) + if stop { + break + } + i++ + } + iterator.Close() +} + // set the delegation func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey)