mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 23:35:19 +00:00
add community multi-spend proposal (#915)
* feat: add community multi-spend proposal type * feat: add handler for community multi-spend proposals * chore: register new community multi-spend proposal * feat: define client for community multi-spend proposal * fix typos in example cli json * fix: register now proposal type with module codec * fix: register community multi-spend proposal with gov router, not committee * fix: define kavadist keeper before referencing it * nit: include deposit in example proposal * nit: update comment * nit: fix error codes * nit: update comments
This commit is contained in:
parent
ffbf31742f
commit
fc85052522
19
app/app.go
19
app/app.go
@ -68,7 +68,7 @@ var (
|
||||
distr.AppModuleBasic{},
|
||||
gov.NewAppModuleBasic(
|
||||
paramsclient.ProposalHandler, distr.ProposalHandler, committee.ProposalHandler,
|
||||
upgradeclient.ProposalHandler,
|
||||
upgradeclient.ProposalHandler, kavadist.ProposalHandler,
|
||||
),
|
||||
params.AppModuleBasic{},
|
||||
crisis.AppModuleBasic{},
|
||||
@ -300,6 +300,14 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
||||
committeeGovRouter,
|
||||
app.paramsKeeper,
|
||||
)
|
||||
app.kavadistKeeper = kavadist.NewKeeper(
|
||||
app.cdc,
|
||||
keys[kavadist.StoreKey],
|
||||
kavadistSubspace,
|
||||
app.supplyKeeper,
|
||||
app.distrKeeper,
|
||||
app.ModuleAccountAddrs(),
|
||||
)
|
||||
|
||||
// create gov keeper with router
|
||||
govRouter := gov.NewRouter()
|
||||
@ -308,7 +316,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
||||
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
|
||||
AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)).
|
||||
AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.upgradeKeeper)).
|
||||
AddRoute(committee.RouterKey, committee.NewProposalHandler(app.committeeKeeper))
|
||||
AddRoute(committee.RouterKey, committee.NewProposalHandler(app.committeeKeeper)).
|
||||
AddRoute(kavadist.RouterKey, kavadist.NewCommunityPoolMultiSpendProposalHandler(app.kavadistKeeper))
|
||||
app.govKeeper = gov.NewKeeper(
|
||||
app.cdc,
|
||||
keys[gov.StoreKey],
|
||||
@ -365,12 +374,6 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptio
|
||||
app.pricefeedKeeper,
|
||||
app.auctionKeeper,
|
||||
)
|
||||
app.kavadistKeeper = kavadist.NewKeeper(
|
||||
app.cdc,
|
||||
keys[kavadist.StoreKey],
|
||||
kavadistSubspace,
|
||||
app.supplyKeeper,
|
||||
)
|
||||
app.incentiveKeeper = incentive.NewKeeper(
|
||||
app.cdc,
|
||||
keys[incentive.StoreKey],
|
||||
|
@ -1,56 +1,69 @@
|
||||
// nolint
|
||||
// autogenerated code using github.com/rigelrozanski/multitool
|
||||
// aliases generated for the following subdirectories:
|
||||
// ALIASGEN: github.com/kava-labs/kava/x/kavadist/types
|
||||
// ALIASGEN: github.com/kava-labs/kava/x/kavadist/keeper
|
||||
// ALIASGEN: github.com/kava-labs/kava/x/kavadist/client
|
||||
package kavadist
|
||||
|
||||
// DO NOT EDIT - generated by aliasgen tool (github.com/rhuairahrighairidh/aliasgen)
|
||||
|
||||
import (
|
||||
"github.com/kava-labs/kava/x/kavadist/client"
|
||||
"github.com/kava-labs/kava/x/kavadist/keeper"
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
const (
|
||||
AttributeKeyInflation = types.AttributeKeyInflation
|
||||
AttributeKeyStatus = types.AttributeKeyStatus
|
||||
AttributeValueInactive = types.AttributeValueInactive
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
EventTypeKavaDist = types.EventTypeKavaDist
|
||||
KavaDistMacc = types.KavaDistMacc
|
||||
ModuleName = types.ModuleName
|
||||
QuerierRoute = types.QuerierRoute
|
||||
QueryGetBalance = types.QueryGetBalance
|
||||
QueryGetParams = types.QueryGetParams
|
||||
RouterKey = types.RouterKey
|
||||
StoreKey = types.StoreKey
|
||||
EventTypeKavaDist = types.EventTypeKavaDist
|
||||
AttributeKeyInflation = types.AttributeKeyInflation
|
||||
AttributeKeyStatus = types.AttributeKeyStatus
|
||||
AttributeValueInactive = types.AttributeValueInactive
|
||||
ModuleName = types.ModuleName
|
||||
StoreKey = types.StoreKey
|
||||
RouterKey = types.RouterKey
|
||||
QuerierRoute = types.QuerierRoute
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
KavaDistMacc = types.KavaDistMacc
|
||||
ProposalTypeCommunityPoolMultiSpend = types.ProposalTypeCommunityPoolMultiSpend
|
||||
QueryGetParams = types.QueryGetParams
|
||||
QueryGetBalance = types.QueryGetBalance
|
||||
)
|
||||
|
||||
var (
|
||||
// function aliases
|
||||
NewKeeper = keeper.NewKeeper
|
||||
NewQuerier = keeper.NewQuerier
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
DefaultParams = types.DefaultParams
|
||||
NewGenesisState = types.NewGenesisState
|
||||
NewParams = types.NewParams
|
||||
NewPeriod = types.NewPeriod
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
RegisterCodec = types.RegisterCodec
|
||||
// functions aliases
|
||||
RegisterCodec = types.RegisterCodec
|
||||
NewGenesisState = types.NewGenesisState
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
NewPeriod = types.NewPeriod
|
||||
NewParams = types.NewParams
|
||||
DefaultParams = types.DefaultParams
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
NewCommunityPoolMultiSpendProposal = types.NewCommunityPoolMultiSpendProposal
|
||||
NewKeeper = keeper.NewKeeper
|
||||
HandleCommunityPoolMultiSpendProposal = keeper.HandleCommunityPoolMultiSpendProposal
|
||||
NewQuerier = keeper.NewQuerier
|
||||
|
||||
// variable aliases
|
||||
CurrentDistPeriodKey = types.CurrentDistPeriodKey
|
||||
DefaultActive = types.DefaultActive
|
||||
DefaultPeriods = types.DefaultPeriods
|
||||
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
||||
GovDenom = types.GovDenom
|
||||
KeyActive = types.KeyActive
|
||||
KeyPeriods = types.KeyPeriods
|
||||
ModuleCdc = types.ModuleCdc
|
||||
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
||||
ModuleCdc = types.ModuleCdc
|
||||
ErrInvalidProposalAmount = types.ErrInvalidProposalAmount
|
||||
ErrEmptyProposalRecipient = types.ErrEmptyProposalRecipient
|
||||
CurrentDistPeriodKey = types.CurrentDistPeriodKey
|
||||
PreviousBlockTimeKey = types.PreviousBlockTimeKey
|
||||
KeyActive = types.KeyActive
|
||||
KeyPeriods = types.KeyPeriods
|
||||
DefaultActive = types.DefaultActive
|
||||
DefaultPeriods = types.DefaultPeriods
|
||||
DefaultPreviousBlockTime = types.DefaultPreviousBlockTime
|
||||
GovDenom = types.GovDenom
|
||||
ProposalHandler = client.ProposalHandler
|
||||
)
|
||||
|
||||
type (
|
||||
Keeper = keeper.Keeper
|
||||
GenesisState = types.GenesisState
|
||||
Params = types.Params
|
||||
Period = types.Period
|
||||
Periods = types.Periods
|
||||
SupplyKeeper = types.SupplyKeeper
|
||||
GenesisState = types.GenesisState
|
||||
Params = types.Params
|
||||
Period = types.Period
|
||||
Periods = types.Periods
|
||||
CommunityPoolMultiSpendProposal = types.CommunityPoolMultiSpendProposal
|
||||
MultiSpendRecipient = types.MultiSpendRecipient
|
||||
MultiSpendRecipients = types.MultiSpendRecipients
|
||||
Keeper = keeper.Keeper
|
||||
)
|
||||
|
93
x/kavadist/client/cli/tx.go
Normal file
93
x/kavadist/client/cli/tx.go
Normal file
@ -0,0 +1,93 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
// GetCmdSubmitProposal implements the command to submit a community-pool multi-spend proposal
|
||||
func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "community-pool-multi-spend [proposal-file]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Submit a community pool multi-spend proposal",
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Submit a community pool multi-spend proposal along with an initial deposit.
|
||||
The proposal details must be supplied via a JSON file.
|
||||
|
||||
Example:
|
||||
$ %s tx gov submit-proposal community-pool-multi-spend <path/to/proposal.json> --from=<key_or_address>
|
||||
|
||||
Where proposal.json contains:
|
||||
|
||||
{
|
||||
"title": "Community Pool Multi-Spend",
|
||||
"description": "Pay many users some KAVA!",
|
||||
"recipient_list": [
|
||||
{
|
||||
"address": "kava1mz2003lathm95n5vnlthmtfvrzrjkrr53j4464",
|
||||
"amount": [
|
||||
{
|
||||
"denom": "ukava",
|
||||
"amount": "1000000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "kava1zqezafa0luyetvtj8j67g336vaqtuudnsjq7vm",
|
||||
"amount": [
|
||||
{
|
||||
"denom": "ukava",
|
||||
"amount": "1000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"deposit": [
|
||||
{
|
||||
"denom": "ukava",
|
||||
"amount": "1000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
version.ClientName,
|
||||
),
|
||||
),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
|
||||
|
||||
proposal, err := ParseCommunityPoolMultiSpendProposalJSON(cdc, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
from := cliCtx.GetFromAddress()
|
||||
content := types.NewCommunityPoolMultiSpendProposal(proposal.Title, proposal.Description, proposal.RecipientList)
|
||||
|
||||
msg := gov.NewMsgSubmitProposal(content, proposal.Deposit, from)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
36
x/kavadist/client/cli/utils.go
Normal file
36
x/kavadist/client/cli/utils.go
Normal file
@ -0,0 +1,36 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// CommunityPoolMultiSpendProposalJSON defines a CommunityPoolMultiSpendProposal with a deposit
|
||||
CommunityPoolMultiSpendProposalJSON struct {
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
RecipientList types.MultiSpendRecipients `json:"recipient_list" yaml:"recipient_list"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
}
|
||||
)
|
||||
|
||||
// ParseCommunityPoolMultiSpendProposalJSON reads and parses a CommunityPoolMultiSpendProposalJSON from a file.
|
||||
func ParseCommunityPoolMultiSpendProposalJSON(cdc *codec.Codec, proposalFile string) (CommunityPoolMultiSpendProposalJSON, error) {
|
||||
proposal := CommunityPoolMultiSpendProposalJSON{}
|
||||
|
||||
contents, err := ioutil.ReadFile(proposalFile)
|
||||
if err != nil {
|
||||
return proposal, err
|
||||
}
|
||||
|
||||
if err := cdc.UnmarshalJSON(contents, &proposal); err != nil {
|
||||
return proposal, err
|
||||
}
|
||||
|
||||
return proposal, nil
|
||||
}
|
13
x/kavadist/client/proposal_handler.go
Normal file
13
x/kavadist/client/proposal_handler.go
Normal file
@ -0,0 +1,13 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
||||
|
||||
"github.com/kava-labs/kava/x/kavadist/client/cli"
|
||||
"github.com/kava-labs/kava/x/kavadist/client/rest"
|
||||
)
|
||||
|
||||
// community-pool multi-spend proposal handler
|
||||
var (
|
||||
ProposalHandler = govclient.NewProposalHandler(cli.GetCmdSubmitProposal, rest.ProposalRESTHandler)
|
||||
)
|
@ -1,12 +1,48 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
// RegisterRoutes registers kavadist-related REST handlers to a router
|
||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
registerQueryRoutes(cliCtx, r)
|
||||
}
|
||||
|
||||
// ProposalRESTHandler returns a ProposalRESTHandler that exposes the community pool multi-spend REST handler with a given sub-route.
|
||||
func ProposalRESTHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: types.ProposalTypeCommunityPoolMultiSpend,
|
||||
Handler: postProposalHandlerFn(cliCtx),
|
||||
}
|
||||
}
|
||||
func postProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req CommunityPoolMultiSpendProposalReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
|
||||
return
|
||||
}
|
||||
req.BaseReq = req.BaseReq.Sanitize()
|
||||
if !req.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
content := types.NewCommunityPoolMultiSpendProposal(req.Title, req.Description, req.RecipientList)
|
||||
msg := gov.NewMsgSubmitProposal(content, req.Deposit, req.Proposer)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
|
||||
}
|
||||
}
|
||||
|
21
x/kavadist/client/rest/utils.go
Normal file
21
x/kavadist/client/rest/utils.go
Normal file
@ -0,0 +1,21 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// CommunityPoolMultiSpendProposalReq defines a community pool multi-spend proposal request body.
|
||||
CommunityPoolMultiSpendProposalReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
RecipientList types.MultiSpendRecipients `json:"recipient_list" yaml:"recipient_list"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
|
||||
}
|
||||
)
|
@ -3,6 +3,9 @@ package kavadist
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
"github.com/kava-labs/kava/x/kavadist/keeper"
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
// NewHandler creates an sdk.Handler for kavadist messages
|
||||
@ -15,3 +18,15 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewCommunityPoolMultiSpendProposalHandler(k Keeper) govtypes.Handler {
|
||||
return func(ctx sdk.Context, content govtypes.Content) error {
|
||||
switch c := content.(type) {
|
||||
case types.CommunityPoolMultiSpendProposal:
|
||||
return keeper.HandleCommunityPoolMultiSpendProposal(ctx, k, c)
|
||||
|
||||
default:
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized kavadist proposal content type: %T", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,19 +17,27 @@ type Keeper struct {
|
||||
cdc *codec.Codec
|
||||
paramSubspace subspace.Subspace
|
||||
supplyKeeper types.SupplyKeeper
|
||||
distKeeper types.DistKeeper
|
||||
|
||||
blacklistedAddrs map[string]bool
|
||||
}
|
||||
|
||||
// NewKeeper creates a new keeper
|
||||
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, sk types.SupplyKeeper) Keeper {
|
||||
func NewKeeper(
|
||||
cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, sk types.SupplyKeeper,
|
||||
dk types.DistKeeper, blacklistedAddrs map[string]bool,
|
||||
) Keeper {
|
||||
if !paramstore.HasKeyTable() {
|
||||
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
|
||||
}
|
||||
|
||||
return Keeper{
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
paramSubspace: paramstore,
|
||||
supplyKeeper: sk,
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
paramSubspace: paramstore,
|
||||
supplyKeeper: sk,
|
||||
distKeeper: dk,
|
||||
blacklistedAddrs: blacklistedAddrs,
|
||||
}
|
||||
}
|
||||
|
||||
|
23
x/kavadist/keeper/proposal_handler.go
Normal file
23
x/kavadist/keeper/proposal_handler.go
Normal file
@ -0,0 +1,23 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/kava-labs/kava/x/kavadist/types"
|
||||
)
|
||||
|
||||
// HandleCommunityPoolMultiSpendProposal is a handler for executing a passed community multi-spend proposal
|
||||
func HandleCommunityPoolMultiSpendProposal(ctx sdk.Context, k Keeper, p types.CommunityPoolMultiSpendProposal) error {
|
||||
for _, receiverInfo := range p.RecipientList {
|
||||
if k.blacklistedAddrs[receiverInfo.Address.String()] {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is blacklisted from receiving external funds", receiverInfo.Address)
|
||||
}
|
||||
err := k.distKeeper.DistributeFromFeePool(ctx, receiverInfo.Amount, receiverInfo.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -14,4 +14,5 @@ func init() {
|
||||
|
||||
// RegisterCodec registers the necessary types for cdp module
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterConcrete(CommunityPoolMultiSpendProposal{}, "kava/CommunityPoolMultiSpendProposal", nil)
|
||||
}
|
||||
|
11
x/kavadist/types/errors.go
Normal file
11
x/kavadist/types/errors.go
Normal file
@ -0,0 +1,11 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// x/kavadist errors
|
||||
var (
|
||||
ErrInvalidProposalAmount = sdkerrors.Register(ModuleName, 2, "invalid community pool multi-spend proposal amount")
|
||||
ErrEmptyProposalRecipient = sdkerrors.Register(ModuleName, 3, "invalid community pool multi-spend proposal recipient")
|
||||
)
|
@ -13,3 +13,8 @@ type SupplyKeeper interface {
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error
|
||||
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error
|
||||
}
|
||||
|
||||
// DistKeeper defines the expected distribution keeper interface
|
||||
type DistKeeper interface {
|
||||
DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) error
|
||||
}
|
||||
|
120
x/kavadist/types/proposal.go
Normal file
120
x/kavadist/types/proposal.go
Normal file
@ -0,0 +1,120 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// ProposalTypeCommunityPoolMultiSpend defines the type for a CommunityPoolMultiSpendProposal
|
||||
ProposalTypeCommunityPoolMultiSpend = "CommunityPoolMultiSpend"
|
||||
)
|
||||
|
||||
// Assert CommunityPoolMultiSpendProposal implements govtypes.Content at compile-time
|
||||
var _ govtypes.Content = CommunityPoolMultiSpendProposal{}
|
||||
|
||||
func init() {
|
||||
govtypes.RegisterProposalType(ProposalTypeCommunityPoolMultiSpend)
|
||||
govtypes.RegisterProposalTypeCodec(CommunityPoolMultiSpendProposal{}, "kava/CommunityPoolMultiSpendProposal")
|
||||
}
|
||||
|
||||
// CommunityPoolMultiSpendProposal spends from the community pool by sending to one or more addresses
|
||||
type CommunityPoolMultiSpendProposal struct {
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
RecipientList MultiSpendRecipients `json:"recipient_list" yaml:"recipient_list"`
|
||||
}
|
||||
|
||||
// NewCommunityPoolMultiSpendProposal creates a new community pool multi-spend proposal.
|
||||
func NewCommunityPoolMultiSpendProposal(title, description string, recipientList MultiSpendRecipients) CommunityPoolMultiSpendProposal {
|
||||
return CommunityPoolMultiSpendProposal{
|
||||
Title: title,
|
||||
Description: description,
|
||||
RecipientList: recipientList}
|
||||
}
|
||||
|
||||
// GetTitle returns the title of a community pool multi-spend proposal.
|
||||
func (csp CommunityPoolMultiSpendProposal) GetTitle() string { return csp.Title }
|
||||
|
||||
// GetDescription returns the description of a community pool multi-spend proposal.
|
||||
func (csp CommunityPoolMultiSpendProposal) GetDescription() string { return csp.Description }
|
||||
|
||||
// GetDescription returns the routing key of a community pool multi-spend proposal.
|
||||
func (csp CommunityPoolMultiSpendProposal) ProposalRoute() string { return RouterKey }
|
||||
|
||||
// ProposalType returns the type of a community pool multi-spend proposal.
|
||||
func (csp CommunityPoolMultiSpendProposal) ProposalType() string {
|
||||
return ProposalTypeCommunityPoolMultiSpend
|
||||
}
|
||||
|
||||
// ValidateBasic stateless validation of a community pool multi-spend proposal.
|
||||
func (csp CommunityPoolMultiSpendProposal) ValidateBasic() error {
|
||||
err := govtypes.ValidateAbstract(csp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := csp.RecipientList.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (csp CommunityPoolMultiSpendProposal) String() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf(`Community Pool Multi Spend Proposal:
|
||||
Title: %s
|
||||
Description: %s
|
||||
Recipient List: %s
|
||||
`, csp.Title, csp.Description, csp.RecipientList))
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// MultiSpendRecipient defines a recipient and the amount of coins they are receiving
|
||||
type MultiSpendRecipient struct {
|
||||
Address sdk.AccAddress `json:"address" yaml:"address"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
}
|
||||
|
||||
// Validate stateless validation of MultiSpendRecipient
|
||||
func (msr MultiSpendRecipient) Validate() error {
|
||||
if !msr.Amount.IsValid() {
|
||||
return ErrInvalidProposalAmount
|
||||
}
|
||||
if msr.Address.Empty() {
|
||||
return ErrEmptyProposalRecipient
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (msr MultiSpendRecipient) String() string {
|
||||
return fmt.Sprintf(`Receiver: %s
|
||||
Amount: %s
|
||||
`, msr.Address, msr.Amount)
|
||||
}
|
||||
|
||||
// MultiSpendRecipients slice of MultiSpendRecipient
|
||||
type MultiSpendRecipients []MultiSpendRecipient
|
||||
|
||||
// Validate stateless validation of MultiSpendRecipients
|
||||
func (msrs MultiSpendRecipients) Validate() error {
|
||||
for _, msr := range msrs {
|
||||
if err := msr.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (msrs MultiSpendRecipients) String() string {
|
||||
out := ""
|
||||
for _, msr := range msrs {
|
||||
out += msr.String()
|
||||
}
|
||||
return out
|
||||
}
|
Loading…
Reference in New Issue
Block a user