Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions proto/atomone/gov/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ message GenesisState {

// last updated value for the dynamic min deposit
LastMinDeposit last_min_deposit = 10;

// last updated value for the dynamic min initial deposit
LastMinDeposit last_min_initial_deposit = 11;
}
31 changes: 30 additions & 1 deletion proto/atomone/gov/v1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,33 @@ message MinDepositThrottler {
uint64 sensitivity_target_distance = 6;
}

message MinInitialDepositThrottler {
// Floor value for the minimum initial deposit required for a proposal to enter the deposit period.
repeated cosmos.base.v1beta1.Coin floor_value = 1
[ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];

// Duration that dictates after how long the dynamic minimum deposit should be recalculated
// for time-based updates.
google.protobuf.Duration update_period = 2 [(gogoproto.stdduration) = true];

// The number of proposals in deposit period the dynamic minimum initial deposit should target.
uint64 target_proposals = 3;

// The ratio of increase for the minimum initial deposit when the number of proposals
// in deposit period exceeds the target by 1.
string increase_ratio = 4 [(cosmos_proto.scalar) = "cosmos.Dec"];

// The ratio of decrease for the minimum initial deposit when the number of proposals
// in deposit period is 1 less than the target.
string decrease_ratio = 5 [(cosmos_proto.scalar) = "cosmos.Dec"];

// A positive integer representing the sensitivity of the dynamic minimum initial
// deposit increase/decrease to the distance from the target number of proposals
// in deposit period. The higher the number, the lower the sensitivity. A value
// of 1 represents the highest sensitivity.
uint64 sensitivity_target_distance = 6;
}

// Params defines the parameters for the x/gov module.
//
// Since: cosmos-sdk 0.47
Expand Down Expand Up @@ -275,7 +302,7 @@ message Params {
string threshold = 5 [(cosmos_proto.scalar) = "cosmos.Dec"];

// The ratio representing the proportion of the deposit value that must be paid at proposal submission.
string min_initial_deposit_ratio = 7 [(cosmos_proto.scalar) = "cosmos.Dec"];
string min_initial_deposit_ratio = 7 [(cosmos_proto.scalar) = "cosmos.Dec", deprecated = true ];

// burn deposits if a proposal does not meet quorum
bool burn_vote_quorum = 13;
Expand Down Expand Up @@ -317,4 +344,6 @@ message Params {
uint64 quorum_check_count = 22;

MinDepositThrottler min_deposit_throttler = 23;

MinInitialDepositThrottler min_initial_deposit_throttler = 24;
}
15 changes: 15 additions & 0 deletions proto/atomone/gov/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ service Query {
rpc MinDeposit(QueryMinDepositRequest) returns (QueryMinDepositResponse) {
option (google.api.http).get = "/atomone/gov/v1/mindeposit";
}

// MinInitialDeposit queries the minimum initial deposit
// currently required for a proposal to be submitted.
rpc MinInitialDeposit(QueryMinInitialDepositRequest) returns (QueryMinInitialDepositResponse) {
option (google.api.http).get = "/atomone/gov/v1/mininitialdeposit";
}
}

// QueryConstitutionRequest is the request type for the Query/Constitution RPC method
Expand Down Expand Up @@ -226,3 +232,12 @@ message QueryMinDepositResponse {
// min_deposit defines the minimum deposit required for a proposal to enter voting period.
repeated cosmos.base.v1beta1.Coin min_deposit = 1 [ (gogoproto.nullable) = false];
}

// QueryMinInitialDepositRequest is the request type for the Query/MinInitialDeposit RPC method.
message QueryMinInitialDepositRequest {}

// QueryMinInitialDepositResponse is the response type for the Query/MinInitialDeposit RPC method.
message QueryMinInitialDepositResponse {
// min_initial_deposit defines the minimum initial deposit required for a proposal to be submitted.
repeated cosmos.base.v1beta1.Coin min_initial_deposit = 1 [ (gogoproto.nullable) = false];
}
7 changes: 5 additions & 2 deletions tests/e2e/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, de

// Refactor to separate method
amnt := sdk.NewInt(10000)
initialDepositAmnt := sdk.NewInt(100)
quorum, _ := sdk.NewDecFromStr("0.000000000000000001")
threshold, _ := sdk.NewDecFromStr("0.000000000000000001")
lawQuorum, _ := sdk.NewDecFromStr("0.000000000000000001")
Expand All @@ -184,13 +185,15 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, de
votingPeriod,
quorum.String(), threshold.String(),
amendmentsQuorum.String(), amendmentsThreshold.String(), lawQuorum.String(), lawThreshold.String(),
sdk.ZeroDec().String(),
// sdk.ZeroDec().String(),
false, false, govv1.DefaultMinDepositRatio.String(),
govv1.DefaultQuorumTimeout, govv1.DefaultMaxVotingPeriodExtension, govv1.DefaultQuorumCheckCount,
sdk.NewCoins(sdk.NewCoin(denom, amnt)), govv1.DefaultMinDepositUpdatePeriod,
govv1.DefaultMinDepositSensitivityTargetDistance,
govv1.DefaultMinDepositIncreaseRatio.String(), govv1.DefaultMinDepositDecreaseRatio.String(),
govv1.DefaultTargetActiveProposals,
govv1.DefaultTargetActiveProposals, sdk.NewCoins(sdk.NewCoin(denom, initialDepositAmnt)), govv1.DefaultMinInitialDepositUpdatePeriod,
govv1.DefaultMinInitialDepositSensitivityTargetDistance, govv1.DefaultMinInitialDepositIncreaseRatio.String(),
govv1.DefaultMinInitialDepositDecreaseRatio.String(), govv1.DefaultTargetProposalsInDepositPeriod,
),
)
govGenState.Constitution = "This is a test constitution"
Expand Down
2 changes: 2 additions & 0 deletions x/gov/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) {
keeper.DeleteAndBurnDeposits(ctx, proposal.Id) // burn the deposit if proposal got removed without getting 100% of the proposal
}

keeper.DecrementInactiveProposalsNumber(ctx)

// called when proposal become inactive
keeper.Hooks().AfterProposalFailedMinDeposit(ctx, proposal.Id)

Expand Down
17 changes: 17 additions & 0 deletions x/gov/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,16 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
newHeader.Time = ctx.BlockHeader().Time.Add(*suite.GovKeeper.GetParams(ctx).MaxDepositPeriod)
ctx = ctx.WithBlockHeader(newHeader)

require.EqualValues(t, 1, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

inactiveQueue = suite.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()

gov.EndBlocker(ctx, suite.GovKeeper)

require.EqualValues(t, 0, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

inactiveQueue = suite.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
Expand Down Expand Up @@ -123,6 +127,8 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()

require.EqualValues(t, 1, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

newProposalMsg2, err := v1.NewMsgSubmitProposal(
[]sdk.Msg{mkTestLegacyContent(t)},
sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)},
Expand All @@ -145,6 +151,8 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()

require.EqualValues(t, 2, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

gov.EndBlocker(ctx, suite.GovKeeper)

inactiveQueue = suite.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
Expand All @@ -159,8 +167,12 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()

require.EqualValues(t, 1, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

gov.EndBlocker(ctx, suite.GovKeeper)

require.EqualValues(t, 0, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

inactiveQueue = suite.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
Expand Down Expand Up @@ -212,6 +224,8 @@ func TestTickPassedDepositPeriod(t *testing.T) {
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()

require.EqualValues(t, 1, suite.GovKeeper.GetInactiveProposalsNumber(ctx))

newDepositMsg := v1.NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)})

res1, err := govMsgSvr.Deposit(sdk.WrapSDKContext(ctx), newDepositMsg)
Expand All @@ -221,6 +235,9 @@ func TestTickPassedDepositPeriod(t *testing.T) {
activeQueue = suite.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()

require.EqualValues(t, 1, suite.GovKeeper.GetInactiveProposalsNumber(ctx))
require.EqualValues(t, 0, suite.GovKeeper.GetActiveProposalsNumber(ctx))
}

func TestTickPassedVotingPeriod(t *testing.T) {
Expand Down
33 changes: 33 additions & 0 deletions x/gov/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdQueryTally(),
GetCmdConstitution(),
GetCmdQueryMinDeposit(),
GetCmdQueryMinInitialDeposit(),
)

return govQueryCmd
Expand Down Expand Up @@ -709,3 +710,35 @@ $ %s query gov min-deposit
},
}
}

// GetCmdQueryMinInitialDeposit implements the query min initial deposit command.
func GetCmdQueryMinInitialDeposit() *cobra.Command {
return &cobra.Command{
Use: "min-initial-deposit",
Args: cobra.ExactArgs(0),
Short: "Query the minimum initial deposit needed for a proposal to enter deposit period",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the minimum initial deposit needed for a proposal to enter deposit period.

Example:
$ %s query gov min-initial-deposit
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
queryClient := v1.NewQueryClient(clientCtx)

resp, err := queryClient.MinInitialDeposit(cmd.Context(), &v1.QueryMinInitialDepositRequest{})
if err != nil {
return err
}

return clientCtx.PrintProto(resp)
},
}
}
60 changes: 60 additions & 0 deletions x/gov/client/cli/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,63 @@ func (s *CLITestSuite) TestCmdGetConstitution() {
})
}
}

func (s *CLITestSuite) TestCmdQueryMinDeposit() {
testCases := []struct {
name string
args []string
expCmdOutput string
}{
{
"query min deposit",
[]string{},
"",
},
{
"query min deposit (json output)",
[]string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
"--output=json",
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryMinDeposit()
cmd.SetArgs(tc.args)
s.Require().Contains(fmt.Sprint(cmd), strings.TrimSpace(tc.expCmdOutput))
})
}
}

func (s *CLITestSuite) TestCmdQueryMinInitialDeposit() {
testCases := []struct {
name string
args []string
expCmdOutput string
}{
{
"query min initial deposit",
[]string{},
"",
},
{
"query min initial deposit (json output)",
[]string{
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
"--output=json",
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryMinInitialDeposit()
cmd.SetArgs(tc.args)
s.Require().Contains(fmt.Sprint(cmd), strings.TrimSpace(tc.expCmdOutput))
})
}
}
26 changes: 19 additions & 7 deletions x/gov/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ func InitGenesis(ctx sdk.Context, ak types.AccountKeeper, bk types.BankKeeper, k
} else {
k.SetLastMinDeposit(ctx, data.Params.MinDepositThrottler.FloorValue, ctx.BlockTime())
}

if data.LastMinInitialDeposit != nil {
k.SetLastMinInitialDeposit(ctx, data.LastMinInitialDeposit.Value, *data.LastMinInitialDeposit.Time)
} else {
k.SetLastMinInitialDeposit(ctx, data.Params.MinInitialDepositThrottler.FloorValue, ctx.BlockTime())
}
}

// ExportGenesis - output genesis parameters
Expand All @@ -108,13 +114,19 @@ func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *v1.GenesisState {
Time: &blockTime,
}

lastMinInitialDeposit := v1.LastMinDeposit{
Value: k.GetMinInitialDeposit(ctx),
Time: &blockTime,
}

return &v1.GenesisState{
StartingProposalId: startingProposalID,
Deposits: proposalsDeposits,
Votes: proposalsVotes,
Proposals: proposals,
Params: &params,
Constitution: constitution,
LastMinDeposit: &lastMinDeposit,
StartingProposalId: startingProposalID,
Deposits: proposalsDeposits,
Votes: proposalsVotes,
Proposals: proposals,
Params: &params,
Constitution: constitution,
LastMinDeposit: &lastMinDeposit,
LastMinInitialDeposit: &lastMinInitialDeposit,
}
}
29 changes: 29 additions & 0 deletions x/gov/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func TestImportExportQueues_ErrorUnconsistentState(t *testing.T) {
Value: sdk.NewCoins(expectedGenState.Params.MinDepositThrottler.FloorValue...),
Time: &time.Time{},
}
expectedGenState.LastMinInitialDeposit = &v1.LastMinDeposit{
Value: expectedGenState.Params.MinInitialDepositThrottler.FloorValue,
Time: &time.Time{},
}
require.Panics(t, func() {
gov.InitGenesis(ctx, suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper, &v1.GenesisState{
Deposits: v1.Deposits{
Expand Down Expand Up @@ -59,6 +63,9 @@ func TestInitGenesis(t *testing.T) {
MinDepositThrottler: &v1.MinDepositThrottler{
FloorValue: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(42))),
},
MinInitialDepositThrottler: &v1.MinInitialDepositThrottler{
FloorValue: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(42))),
},
}
quorumTimeout = time.Hour * 20
paramsWithQuorumCheckEnabled = &v1.Params{
Expand All @@ -67,6 +74,9 @@ func TestInitGenesis(t *testing.T) {
MinDepositThrottler: &v1.MinDepositThrottler{
FloorValue: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(42))),
},
MinInitialDepositThrottler: &v1.MinInitialDepositThrottler{
FloorValue: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(42))),
},
}

depositAmount = sdk.Coins{
Expand Down Expand Up @@ -175,6 +185,9 @@ func TestInitGenesis(t *testing.T) {
lmdCoins, lmdTime := s.GovKeeper.GetLastMinDeposit(ctx)
assert.EqualValues(t, p.MinDepositThrottler.FloorValue, lmdCoins)
assert.Equal(t, ctx.BlockTime(), lmdTime)
lmidCoins, lmidTime := s.GovKeeper.GetLastMinInitialDeposit(ctx)
assert.EqualValues(t, p.MinInitialDepositThrottler.FloorValue, lmidCoins)
assert.Equal(t, ctx.BlockTime(), lmidTime)
},
},
{
Expand All @@ -193,6 +206,22 @@ func TestInitGenesis(t *testing.T) {
assert.Equal(t, utcTime, lmdTime)
},
},
{
name: "ok: genesis with last min initial deposit",
genesis: v1.GenesisState{
Params: params,
LastMinInitialDeposit: &v1.LastMinDeposit{
Value: sdk.NewCoins(sdk.NewInt64Coin("xxx", 1)),
Time: &utcTime,
},
},
assert: func(t *testing.T, ctx sdk.Context, s suite) {
t.Helper()
lmidCoins, lmidTime := s.GovKeeper.GetLastMinInitialDeposit(ctx)
assert.EqualValues(t, sdk.NewCoins(sdk.NewInt64Coin("xxx", 1)), lmidCoins)
assert.Equal(t, utcTime, lmidTime)
},
},
{
name: "fail: genesis with deposits but module balance is not equal to total deposits",
moduleBalance: depositAmount,
Expand Down
Loading
Loading