func (k Keeper) Stake(ctx sdk.Context, farmerAcc sdk.AccAddress, amount sdk.Coins) error {
	if err := k.ReserveStakingCoins(ctx, farmerAcc, amount); err != nil {
		return err
	}
	numStakingCoinDenoms := 0
	for _, coin := range amount {
		queuedStaking, found := k.GetQueuedStaking(ctx, coin.Denom, farmerAcc)
		if !found {
			queuedStaking.Amount = sdk.ZeroInt()
		}
		queuedStaking.Amount = queuedStaking.Amount.Add(coin.Amount)
		k.SetQueuedStaking(ctx, coin.Denom, farmerAcc, queuedStaking)
		_, found = k.GetStaking(ctx, coin.Denom, farmerAcc)
		if found {
			numStakingCoinDenoms++
		}
	}
	if numStakingCoinDenoms > 0 {
		params := k.GetParams(ctx)
		ctx.GasMeter().ConsumeGas(sdk.Gas(numStakingCoinDenoms)*params.DelayedStakingGasFee, "DelayedStakingGasFee")
	}
	ctx.EventManager().EmitEvents(sdk.Events{
		sdk.NewEvent(
			types.EventTypeStake,
			sdk.NewAttribute(types.AttributeKeyFarmer, farmerAcc.String()),
			sdk.NewAttribute(types.AttributeKeyStakingCoins, amount.String()),
		),
	})
	return nil
}
Stake stores staking coins to queued coins, and it will be processed in the next epoch.
package keeper
import (
	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	"github.com/tendermint/farming/x/farming/types"
)
func (k Keeper) GetStaking(ctx sdk.Context, stakingCoinDenom string, farmerAcc sdk.AccAddress) (staking types.Staking, found bool) {
	store := ctx.KVStore(k.storeKey)
	bz := store.Get(types.GetStakingKey(stakingCoinDenom, farmerAcc))
	if bz == nil {
		return
	}
	k.cdc.MustUnmarshal(bz, &staking)
	found = true
	return
}
func (k Keeper) SetStaking(ctx sdk.Context, stakingCoinDenom string, farmerAcc sdk.AccAddress, staking types.Staking) {
	store := ctx.KVStore(k.storeKey)
	bz := k.cdc.MustMarshal(&staking)
	store.Set(types.GetStakingKey(stakingCoinDenom, farmerAcc), bz)
	store.Set(types.GetStakingIndexKey(farmerAcc, stakingCoinDenom), []byte{})
}
func (k Keeper) DeleteStaking(ctx sdk.Context, stakingCoinDenom string, farmerAcc sdk.AccAddress) {
	store := ctx.KVStore(k.storeKey)
	store.Delete(types.GetStakingKey(stakingCoinDenom, farmerAcc))
	store.Delete(types.GetStakingIndexKey(farmerAcc, stakingCoinDenom))
}
func (k Keeper) IterateStakings(ctx sdk.Context, cb func(stakingCoinDenom string, farmerAcc sdk.AccAddress, staking types.Staking) (stop bool)) {
	store := ctx.KVStore(k.storeKey)
	iter := sdk.KVStorePrefixIterator(store, types.StakingKeyPrefix)
	defer iter.Close()
	for ; iter.Valid(); iter.Next() {
		var staking types.Staking
		k.cdc.MustUnmarshal(iter.Value(), &staking)
		stakingCoinDenom, farmerAcc := types.ParseStakingKey(iter.Key())
		if cb(stakingCoinDenom, farmerAcc, staking) {
			break
		}
	}
}
func (k Keeper) IterateStakingsByFarmer(ctx sdk.Context, farmerAcc sdk.AccAddress, cb func(stakingCoinDenom string, staking types.Staking) (stop bool)) {
	store := ctx.KVStore(k.storeKey)
	iter := sdk.KVStorePrefixIterator(store, types.GetStakingsByFarmerPrefix(farmerAcc))
	defer iter.Close()
	for ; iter.Valid(); iter.Next() {
		farmerAcc, stakingCoinDenom := types.ParseStakingIndexKey(iter.Key())
		staking, _ := k.GetStaking(ctx, stakingCoinDenom, farmerAcc)
		if cb(stakingCoinDenom, staking) {
			break
		}
	}
}
func (k Keeper) GetAllStakedCoinsByFarmer(ctx sdk.Context, farmerAcc sdk.AccAddress) sdk.Coins {
	stakedCoins := sdk.NewCoins()
	k.IterateStakingsByFarmer(ctx, farmerAcc, func(stakingCoinDenom string, staking types.Staking) (stop bool) {
		stakedCoins = stakedCoins.Add(sdk.NewCoin(stakingCoinDenom, staking.Amount))
		return false
	})
	return stakedCoins
}
func (k Keeper) GetQueuedStaking(ctx sdk.Context, stakingCoinDenom string, farmerAcc sdk.AccAddress) (queuedStaking types.QueuedStaking, found bool) {
	store := ctx.KVStore(k.storeKey)
	bz := store.Get(types.GetQueuedStakingKey(stakingCoinDenom, farmerAcc))
	if bz == nil {
		return
	}
	k.cdc.MustUnmarshal(bz, &queuedStaking)
	found = true
	return
}
func (k Keeper) SetQueuedStaking(ctx sdk.Context, stakingCoinDenom string, farmerAcc sdk.AccAddress, queuedStaking types.QueuedStaking) {
	store := ctx.KVStore(k.storeKey)
	bz := k.cdc.MustMarshal(&queuedStaking)
	store.Set(types.GetQueuedStakingKey(stakingCoinDenom, farmerAcc), bz)
	store.Set(types.GetQueuedStakingIndexKey(farmerAcc, stakingCoinDenom), []byte{})
}
func (k Keeper) DeleteQueuedStaking(ctx sdk.Context, stakingCoinDenom string, farmerAcc sdk.AccAddress) {
	store := ctx.KVStore(k.storeKey)
	store.Delete(types.GetQueuedStakingKey(stakingCoinDenom, farmerAcc))
	store.Delete(types.GetQueuedStakingIndexKey(farmerAcc, stakingCoinDenom))
}
func (k Keeper) IterateQueuedStakings(ctx sdk.Context, cb func(stakingCoinDenom string, farmerAcc sdk.AccAddress, queuedStaking types.QueuedStaking) (stop bool)) {
	store := ctx.KVStore(k.storeKey)
	iter := sdk.KVStorePrefixIterator(store, types.QueuedStakingKeyPrefix)
	defer iter.Close()
	for ; iter.Valid(); iter.Next() {
		var queuedStaking types.QueuedStaking
		k.cdc.MustUnmarshal(iter.Value(), &queuedStaking)
		stakingCoinDenom, farmerAcc := types.ParseQueuedStakingKey(iter.Key())
		if cb(stakingCoinDenom, farmerAcc, queuedStaking) {
			break
		}
	}
}
func (k Keeper) IterateQueuedStakingsByFarmer(ctx sdk.Context, farmerAcc sdk.AccAddress, cb func(stakingCoinDenom string, queuedStaking types.QueuedStaking) (stop bool)) {
	store := ctx.KVStore(k.storeKey)
	iter := sdk.KVStorePrefixIterator(store, types.GetQueuedStakingByFarmerPrefix(farmerAcc))
	defer iter.Close()
	for ; iter.Valid(); iter.Next() {
		farmerAcc, stakingCoinDenom := types.ParseQueuedStakingIndexKey(iter.Key())
		queuedStaking, _ := k.GetQueuedStaking(ctx, stakingCoinDenom, farmerAcc)
		if cb(stakingCoinDenom, queuedStaking) {
			break
		}
	}
}
func (k Keeper) GetAllQueuedCoinsByFarmer(ctx sdk.Context, farmerAcc sdk.AccAddress) sdk.Coins {
	stakedCoins := sdk.NewCoins()
	k.IterateQueuedStakingsByFarmer(ctx, farmerAcc, func(stakingCoinDenom string, queuedStaking types.QueuedStaking) (stop bool) {
		stakedCoins = stakedCoins.Add(sdk.NewCoin(stakingCoinDenom, queuedStaking.Amount))
		return false
	})
	return stakedCoins
}
func (k Keeper) GetTotalStakings(ctx sdk.Context, stakingCoinDenom string) (totalStakings types.TotalStakings, found bool) {
	store := ctx.KVStore(k.storeKey)
	bz := store.Get(types.GetTotalStakingsKey(stakingCoinDenom))
	if bz == nil {
		return
	}
	k.cdc.MustUnmarshal(bz, &totalStakings)
	found = true
	return
}
func (k Keeper) SetTotalStakings(ctx sdk.Context, stakingCoinDenom string, totalStakings types.TotalStakings) {
	store := ctx.KVStore(k.storeKey)
	bz := k.cdc.MustMarshal(&totalStakings)
	store.Set(types.GetTotalStakingsKey(stakingCoinDenom), bz)
}
func (k Keeper) DeleteTotalStakings(ctx sdk.Context, stakingCoinDenom string) {
	store := ctx.KVStore(k.storeKey)
	store.Delete(types.GetTotalStakingsKey(stakingCoinDenom))
}
func (k Keeper) IncreaseTotalStakings(ctx sdk.Context, stakingCoinDenom string, amount sdk.Int) {
	totalStaking, found := k.GetTotalStakings(ctx, stakingCoinDenom)
	if !found {
		totalStaking.Amount = sdk.ZeroInt()
	}
	totalStaking.Amount = totalStaking.Amount.Add(amount)
	k.SetTotalStakings(ctx, stakingCoinDenom, totalStaking)
}
func (k Keeper) DecreaseTotalStakings(ctx sdk.Context, stakingCoinDenom string, amount sdk.Int) {
	totalStaking, found := k.GetTotalStakings(ctx, stakingCoinDenom)
	if !found {
		panic("total stakings not found")
	}
	if totalStaking.Amount.Equal(amount) {
		k.DeleteTotalStakings(ctx, stakingCoinDenom)
	} else {
		totalStaking.Amount = totalStaking.Amount.Sub(amount)
		k.SetTotalStakings(ctx, stakingCoinDenom, totalStaking)
	}
}
func (k Keeper) IterateTotalStakings(ctx sdk.Context, cb func(stakingCoinDenom string, totalStakings types.TotalStakings) (stop bool)) {
	store := ctx.KVStore(k.storeKey)
	iter := sdk.KVStorePrefixIterator(store, types.TotalStakingKeyPrefix)
	defer iter.Close()
	for ; iter.Valid(); iter.Next() {
		var totalStakings types.TotalStakings
		k.cdc.MustUnmarshal(iter.Value(), &totalStakings)
		stakingCoinDenom := types.ParseTotalStakingsKey(iter.Key())
		if cb(stakingCoinDenom, totalStakings) {
			break
		}
	}
}
func (k Keeper) ReserveStakingCoins(ctx sdk.Context, farmerAcc sdk.AccAddress, stakingCoins sdk.Coins) error {
	if err := k.bankKeeper.SendCoins(ctx, farmerAcc, k.GetStakingReservePoolAcc(ctx), stakingCoins); err != nil {
		return err
	}
	return nil
}
func (k Keeper) ReleaseStakingCoins(ctx sdk.Context, farmerAcc sdk.AccAddress, unstakingCoins sdk.Coins) error {
	if err := k.bankKeeper.SendCoins(ctx, k.GetStakingReservePoolAcc(ctx), farmerAcc, unstakingCoins); err != nil {
		return err
	}
	return nil
}