mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 08:57:27 +00:00 
			
		
		
		
	Tally handler with liquid staking support (#1307)
* tally handler with liquid staking support * clean up * update for liquid keeper changes * switch to tagged cosmos-sdk for tallying updates Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com>
This commit is contained in:
		
							parent
							
								
									b68685af32
								
							
						
					
					
						commit
						314f733cb8
					
				@ -674,6 +674,13 @@ func NewApp(
 | 
				
			|||||||
	app.savingsKeeper = *savingsKeeper.SetHooks(savingstypes.NewMultiSavingsHooks(app.incentiveKeeper.Hooks()))
 | 
						app.savingsKeeper = *savingsKeeper.SetHooks(savingstypes.NewMultiSavingsHooks(app.incentiveKeeper.Hooks()))
 | 
				
			||||||
	app.earnKeeper = *earnKeeper.SetHooks(app.incentiveKeeper.Hooks())
 | 
						app.earnKeeper = *earnKeeper.SetHooks(app.incentiveKeeper.Hooks())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// override x/gov tally handler with custom implementation
 | 
				
			||||||
 | 
						tallyHandler := NewTallyHandler(
 | 
				
			||||||
 | 
							app.govKeeper, app.stakingKeeper, app.savingsKeeper, app.earnKeeper,
 | 
				
			||||||
 | 
							app.liquidKeeper, app.bankKeeper,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						app.govKeeper.SetTallyHandler(tallyHandler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create the module manager (Note: Any module instantiated in the module manager that is later modified
 | 
						// create the module manager (Note: Any module instantiated in the module manager that is later modified
 | 
				
			||||||
	// must be passed by reference here.)
 | 
						// must be passed by reference here.)
 | 
				
			||||||
	app.mm = module.NewManager(
 | 
						app.mm = module.NewManager(
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										253
									
								
								app/tally_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								app/tally_handler.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,253 @@
 | 
				
			|||||||
 | 
					package app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
 | 
				
			||||||
 | 
						govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
 | 
				
			||||||
 | 
						"github.com/cosmos/cosmos-sdk/x/gov/types"
 | 
				
			||||||
 | 
						govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
 | 
				
			||||||
 | 
						stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
 | 
				
			||||||
 | 
						stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
 | 
				
			||||||
 | 
						earnkeeper "github.com/kava-labs/kava/x/earn/keeper"
 | 
				
			||||||
 | 
						liquidkeeper "github.com/kava-labs/kava/x/liquid/keeper"
 | 
				
			||||||
 | 
						liquidtypes "github.com/kava-labs/kava/x/liquid/types"
 | 
				
			||||||
 | 
						savingskeeper "github.com/kava-labs/kava/x/savings/keeper"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ govtypes.TallyHandler = TallyHandler{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TallyHandler is the tally handler for kava
 | 
				
			||||||
 | 
					type TallyHandler struct {
 | 
				
			||||||
 | 
						gk  govkeeper.Keeper
 | 
				
			||||||
 | 
						stk stakingkeeper.Keeper
 | 
				
			||||||
 | 
						svk savingskeeper.Keeper
 | 
				
			||||||
 | 
						ek  earnkeeper.Keeper
 | 
				
			||||||
 | 
						lk  liquidkeeper.Keeper
 | 
				
			||||||
 | 
						bk  bankkeeper.Keeper
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewTallyHandler creates a new tally handler.
 | 
				
			||||||
 | 
					func NewTallyHandler(
 | 
				
			||||||
 | 
						gk govkeeper.Keeper, stk stakingkeeper.Keeper, svk savingskeeper.Keeper,
 | 
				
			||||||
 | 
						ek earnkeeper.Keeper, lk liquidkeeper.Keeper, bk bankkeeper.Keeper,
 | 
				
			||||||
 | 
					) TallyHandler {
 | 
				
			||||||
 | 
						return TallyHandler{
 | 
				
			||||||
 | 
							gk:  gk,
 | 
				
			||||||
 | 
							stk: stk,
 | 
				
			||||||
 | 
							svk: svk,
 | 
				
			||||||
 | 
							ek:  ek,
 | 
				
			||||||
 | 
							lk:  lk,
 | 
				
			||||||
 | 
							bk:  bk,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (th TallyHandler) Tally(ctx sdk.Context, proposal types.Proposal) (passes bool, burnDeposits bool, tallyResults types.TallyResult) {
 | 
				
			||||||
 | 
						results := make(map[types.VoteOption]sdk.Dec)
 | 
				
			||||||
 | 
						results[types.OptionYes] = sdk.ZeroDec()
 | 
				
			||||||
 | 
						results[types.OptionAbstain] = sdk.ZeroDec()
 | 
				
			||||||
 | 
						results[types.OptionNo] = sdk.ZeroDec()
 | 
				
			||||||
 | 
						results[types.OptionNoWithVeto] = sdk.ZeroDec()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						totalVotingPower := sdk.ZeroDec()
 | 
				
			||||||
 | 
						currValidators := make(map[string]types.ValidatorGovInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// fetch all the bonded validators, insert them into currValidators
 | 
				
			||||||
 | 
						th.stk.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) {
 | 
				
			||||||
 | 
							currValidators[validator.GetOperator().String()] = types.NewValidatorGovInfo(
 | 
				
			||||||
 | 
								validator.GetOperator(),
 | 
				
			||||||
 | 
								validator.GetBondedTokens(),
 | 
				
			||||||
 | 
								validator.GetDelegatorShares(),
 | 
				
			||||||
 | 
								sdk.ZeroDec(),
 | 
				
			||||||
 | 
								types.WeightedVoteOptions{},
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						th.gk.IterateVotes(ctx, proposal.ProposalId, func(vote types.Vote) bool {
 | 
				
			||||||
 | 
							// if validator, just record it in the map
 | 
				
			||||||
 | 
							voter, err := sdk.AccAddressFromBech32(vote.Voter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								panic(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							valAddrStr := sdk.ValAddress(voter.Bytes()).String()
 | 
				
			||||||
 | 
							if val, ok := currValidators[valAddrStr]; ok {
 | 
				
			||||||
 | 
								val.Vote = vote.Options
 | 
				
			||||||
 | 
								currValidators[valAddrStr] = val
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// iterate over all delegations from voter, deduct from any delegated-to validators
 | 
				
			||||||
 | 
							th.stk.IterateDelegations(ctx, voter, func(index int64, delegation stakingtypes.DelegationI) (stop bool) {
 | 
				
			||||||
 | 
								valAddrStr := delegation.GetValidatorAddr().String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if val, ok := currValidators[valAddrStr]; ok {
 | 
				
			||||||
 | 
									// There is no need to handle the special case that validator address equal to voter address.
 | 
				
			||||||
 | 
									// Because voter's voting power will tally again even if there will deduct voter's voting power from validator.
 | 
				
			||||||
 | 
									val.DelegatorDeductions = val.DelegatorDeductions.Add(delegation.GetShares())
 | 
				
			||||||
 | 
									currValidators[valAddrStr] = val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// delegation shares * bonded / total shares
 | 
				
			||||||
 | 
									votingPower := delegation.GetShares().MulInt(val.BondedTokens).Quo(val.DelegatorShares)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for _, option := range vote.Options {
 | 
				
			||||||
 | 
										subPower := votingPower.Mul(option.Weight)
 | 
				
			||||||
 | 
										results[option.Option] = results[option.Option].Add(subPower)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									totalVotingPower = totalVotingPower.Add(votingPower)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// get voter bkava and update total voting power and results
 | 
				
			||||||
 | 
							addrBkava := th.getAddrBkava(ctx, voter).toCoins()
 | 
				
			||||||
 | 
							for _, coin := range addrBkava {
 | 
				
			||||||
 | 
								valAddr, err := liquidtypes.ParseLiquidStakingTokenDenom(coin.Denom)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// reduce delegator shares by the amount of voter bkava for the validator
 | 
				
			||||||
 | 
								valAddrStr := valAddr.String()
 | 
				
			||||||
 | 
								if val, ok := currValidators[valAddrStr]; ok {
 | 
				
			||||||
 | 
									val.DelegatorDeductions = val.DelegatorDeductions.Add(coin.Amount.ToDec())
 | 
				
			||||||
 | 
									currValidators[valAddrStr] = val
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// votingPower = amount of ukava coin
 | 
				
			||||||
 | 
								stakedCoins, err := th.lk.GetStakedTokensForDerivatives(ctx, sdk.NewCoins(coin))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									// error is returned only if the bkava denom is incorrect, which should never happen here.
 | 
				
			||||||
 | 
									panic(err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								votingPower := stakedCoins.Amount.ToDec()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, option := range vote.Options {
 | 
				
			||||||
 | 
									subPower := votingPower.Mul(option.Weight)
 | 
				
			||||||
 | 
									results[option.Option] = results[option.Option].Add(subPower)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								totalVotingPower = totalVotingPower.Add(votingPower)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							th.gk.DeleteVote(ctx, vote.ProposalId, voter)
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// iterate over the validators again to tally their voting power
 | 
				
			||||||
 | 
						for _, val := range currValidators {
 | 
				
			||||||
 | 
							if len(val.Vote) == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sharesAfterDeductions := val.DelegatorShares.Sub(val.DelegatorDeductions)
 | 
				
			||||||
 | 
							votingPower := sharesAfterDeductions.MulInt(val.BondedTokens).Quo(val.DelegatorShares)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, option := range val.Vote {
 | 
				
			||||||
 | 
								subPower := votingPower.Mul(option.Weight)
 | 
				
			||||||
 | 
								results[option.Option] = results[option.Option].Add(subPower)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							totalVotingPower = totalVotingPower.Add(votingPower)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tallyParams := th.gk.GetTallyParams(ctx)
 | 
				
			||||||
 | 
						tallyResults = types.NewTallyResultFromMap(results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: Upgrade the spec to cover all of these cases & remove pseudocode.
 | 
				
			||||||
 | 
						// If there is no staked coins, the proposal fails
 | 
				
			||||||
 | 
						if th.stk.TotalBondedTokens(ctx).IsZero() {
 | 
				
			||||||
 | 
							return false, false, tallyResults
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there is not enough quorum of votes, the proposal fails
 | 
				
			||||||
 | 
						percentVoting := totalVotingPower.Quo(th.stk.TotalBondedTokens(ctx).ToDec())
 | 
				
			||||||
 | 
						if percentVoting.LT(tallyParams.Quorum) {
 | 
				
			||||||
 | 
							return false, true, tallyResults
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If no one votes (everyone abstains), proposal fails
 | 
				
			||||||
 | 
						if totalVotingPower.Sub(results[types.OptionAbstain]).Equal(sdk.ZeroDec()) {
 | 
				
			||||||
 | 
							return false, false, tallyResults
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If more than 1/3 of voters veto, proposal fails
 | 
				
			||||||
 | 
						if results[types.OptionNoWithVeto].Quo(totalVotingPower).GT(tallyParams.VetoThreshold) {
 | 
				
			||||||
 | 
							return false, true, tallyResults
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If more than 1/2 of non-abstaining voters vote Yes, proposal passes
 | 
				
			||||||
 | 
						if results[types.OptionYes].Quo(totalVotingPower.Sub(results[types.OptionAbstain])).GT(tallyParams.Threshold) {
 | 
				
			||||||
 | 
							return true, false, tallyResults
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If more than 1/2 of non-abstaining voters vote No, proposal fails
 | 
				
			||||||
 | 
						return false, false, tallyResults
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// bkavaByDenom a map of the bkava denom and the amount of bkava for that denom.
 | 
				
			||||||
 | 
					type bkavaByDenom map[string]sdk.Int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (bkavaMap bkavaByDenom) add(coin sdk.Coin) {
 | 
				
			||||||
 | 
						_, found := bkavaMap[coin.Denom]
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							bkavaMap[coin.Denom] = sdk.ZeroInt()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bkavaMap[coin.Denom].Add(coin.Amount)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (bkavaMap bkavaByDenom) toCoins() sdk.Coins {
 | 
				
			||||||
 | 
						coins := sdk.Coins{}
 | 
				
			||||||
 | 
						for denom, amt := range bkavaMap {
 | 
				
			||||||
 | 
							coins.Add(sdk.NewCoin(denom, amt))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return coins.Sort()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// getAddrBkava returns a map of validator address & the amount of bkava
 | 
				
			||||||
 | 
					// of the addr for each validator.
 | 
				
			||||||
 | 
					func (th TallyHandler) getAddrBkava(ctx sdk.Context, addr sdk.AccAddress) bkavaByDenom {
 | 
				
			||||||
 | 
						results := make(bkavaByDenom)
 | 
				
			||||||
 | 
						th.addBkavaFromWallet(ctx, addr, results)
 | 
				
			||||||
 | 
						th.addBkavaFromSavings(ctx, addr, results)
 | 
				
			||||||
 | 
						th.addBkavaFromEarn(ctx, addr, results)
 | 
				
			||||||
 | 
						return results
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// addBkavaFromWallet adds all addr balances of bkava in x/bank.
 | 
				
			||||||
 | 
					func (th TallyHandler) addBkavaFromWallet(ctx sdk.Context, addr sdk.AccAddress, bkava bkavaByDenom) {
 | 
				
			||||||
 | 
						coins := th.bk.GetAllBalances(ctx, addr)
 | 
				
			||||||
 | 
						for _, coin := range coins {
 | 
				
			||||||
 | 
							if th.lk.IsDerivativeDenom(ctx, coin.Denom) {
 | 
				
			||||||
 | 
								bkava.add(coin)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// addBkavaFromSavings adds all addr deposits of bkava in x/savings.
 | 
				
			||||||
 | 
					func (th TallyHandler) addBkavaFromSavings(ctx sdk.Context, addr sdk.AccAddress, bkava bkavaByDenom) {
 | 
				
			||||||
 | 
						deposit, found := th.svk.GetDeposit(ctx, addr)
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, coin := range deposit.Amount {
 | 
				
			||||||
 | 
							if th.lk.IsDerivativeDenom(ctx, coin.Denom) {
 | 
				
			||||||
 | 
								bkava.add(coin)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// addBkavaFromEarn adds all addr deposits of bkava in x/earn.
 | 
				
			||||||
 | 
					func (th TallyHandler) addBkavaFromEarn(ctx sdk.Context, addr sdk.AccAddress, bkava bkavaByDenom) {
 | 
				
			||||||
 | 
						shares, found := th.ek.GetVaultAccountShares(ctx, addr)
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, share := range shares {
 | 
				
			||||||
 | 
							if th.lk.IsDerivativeDenom(ctx, share.Denom) {
 | 
				
			||||||
 | 
								if coin, err := th.ek.ConvertToAssets(ctx, share); err != nil {
 | 
				
			||||||
 | 
									bkava.add(coin)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -157,7 +157,7 @@ replace (
 | 
				
			|||||||
	// Use the cosmos keyring code
 | 
						// Use the cosmos keyring code
 | 
				
			||||||
	github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
 | 
						github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
 | 
				
			||||||
	// Use cosmos-sdk fork with backported fix for unsafe-reset-all
 | 
						// Use cosmos-sdk fork with backported fix for unsafe-reset-all
 | 
				
			||||||
	github.com/cosmos/cosmos-sdk => github.com/kava-labs/cosmos-sdk v0.45.4-kava.3
 | 
						github.com/cosmos/cosmos-sdk => github.com/kava-labs/cosmos-sdk v0.45.4-kava.4
 | 
				
			||||||
	// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
 | 
						// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
 | 
				
			||||||
	github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0
 | 
						github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0
 | 
				
			||||||
	// Use the cosmos modified protobufs
 | 
						// Use the cosmos modified protobufs
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -696,8 +696,8 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
 | 
				
			|||||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
 | 
					github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
 | 
				
			||||||
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
 | 
					github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
 | 
				
			||||||
github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
 | 
					github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
 | 
				
			||||||
github.com/kava-labs/cosmos-sdk v0.45.4-kava.3 h1:U4esIl4rzu9sApLFYGwbccPQTQdRg6C9exUVrokqSHY=
 | 
					github.com/kava-labs/cosmos-sdk v0.45.4-kava.4 h1:zAxlDE8VtAPnVjC4hwMqEzFA0H18o+pQlP4aviLKOYc=
 | 
				
			||||||
github.com/kava-labs/cosmos-sdk v0.45.4-kava.3/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc=
 | 
					github.com/kava-labs/cosmos-sdk v0.45.4-kava.4/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc=
 | 
				
			||||||
github.com/kava-labs/tm-db v0.6.7-kava.1 h1:7cVYlvWx1yP+gGdaAWcfm6NwMLzf4z6DxXguWn3+O3w=
 | 
					github.com/kava-labs/tm-db v0.6.7-kava.1 h1:7cVYlvWx1yP+gGdaAWcfm6NwMLzf4z6DxXguWn3+O3w=
 | 
				
			||||||
github.com/kava-labs/tm-db v0.6.7-kava.1/go.mod h1:HVZfZzWXuqWseXQVplxsWXK6kLHLkk3kQB6c+nuSZvk=
 | 
					github.com/kava-labs/tm-db v0.6.7-kava.1/go.mod h1:HVZfZzWXuqWseXQVplxsWXK6kLHLkk3kQB6c+nuSZvk=
 | 
				
			||||||
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM=
 | 
					github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM=
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user