-
Notifications
You must be signed in to change notification settings - Fork 624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CL Incentives] Implement CreateIncentive
logic and message
#4519
Changes from all commits
620602b
6e1c365
43573c3
fe7a39f
efe72bc
3abe2a8
580a7ca
21268ba
c863344
a8c6d4c
2acb254
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,4 +132,57 @@ message MsgCollectIncentivesResponse { | |
(gogoproto.moretags) = "yaml:\"collected_incentives\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
} | ||
|
||
// ===================== MsgCreateIncentive | ||
message MsgCreateIncentive { | ||
uint64 pool_id = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ]; | ||
string sender = 2 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; | ||
string incentive_denom = 3; | ||
string incentive_amount = 4 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", | ||
(gogoproto.moretags) = "yaml:\"incentive_amount\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
string emission_rate = 5 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", | ||
(gogoproto.moretags) = "yaml:\"emission_rate\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
google.protobuf.Timestamp start_time = 6 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.stdtime) = true, | ||
(gogoproto.moretags) = "yaml:\"start_time\"" | ||
]; | ||
google.protobuf.Duration min_uptime = 7 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.stdduration) = true, | ||
(gogoproto.jsontag) = "duration,omitempty", | ||
(gogoproto.moretags) = "yaml:\"min_uptime\"" | ||
]; | ||
} | ||
|
||
message MsgCreateIncentiveResponse { | ||
string incentive_denom = 1; | ||
string incentive_amount = 2 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", | ||
(gogoproto.moretags) = "yaml:\"incentive_amount\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
Comment on lines
+166
to
+171
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this |
||
string emission_rate = 3 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", | ||
(gogoproto.moretags) = "yaml:\"emission_rate\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
google.protobuf.Timestamp start_time = 4 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.stdtime) = true, | ||
(gogoproto.moretags) = "yaml:\"start_time\"" | ||
]; | ||
google.protobuf.Duration min_uptime = 5 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.stdduration) = true, | ||
(gogoproto.jsontag) = "duration,omitempty", | ||
(gogoproto.moretags) = "yaml:\"min_uptime\"" | ||
]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ func NewTxCmd() *cobra.Command { | |
osmocli.AddTxCmd(txCmd, NewCreateConcentratedPoolCmd) | ||
osmocli.AddTxCmd(txCmd, NewCollectFeesCmd) | ||
osmocli.AddTxCmd(txCmd, NewCollectIncentivesCmd) | ||
osmocli.AddTxCmd(txCmd, NewCreateIncentiveCmd) | ||
return txCmd | ||
} | ||
|
||
|
@@ -71,3 +72,13 @@ func NewCollectIncentivesCmd() (*osmocli.TxCliDesc, *types.MsgCollectIncentives) | |
Flags: osmocli.FlagDesc{RequiredFlags: []*flag.FlagSet{FlagSetJustPoolId()}}, | ||
}, &types.MsgCollectIncentives{} | ||
} | ||
|
||
func NewCreateIncentiveCmd() (*osmocli.TxCliDesc, *types.MsgCreateIncentive) { | ||
return &osmocli.TxCliDesc{ | ||
Use: "create-incentive [incentive-denom] [incentive-amount] [emission-rate] [start-time] [min-uptime]", | ||
Short: "create an incentive record to emit incentives (per second) to a given pool", | ||
Example: "create-incentive uosmo 69082 0.02 100 2023-03-03 03:20:35.419543805 24h --pool-id 1 --from val --chain-id osmosis-1", | ||
CustomFlagOverrides: poolIdFlagOverride, | ||
Flags: osmocli.FlagDesc{RequiredFlags: []*flag.FlagSet{FlagSetJustPoolId()}}, | ||
}, &types.MsgCreateIncentive{} | ||
Comment on lines
+82
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not blocking, but we have been trying to move away from mandatory flags, would be nice if we could just make poolId be part of the create incentive message |
||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -501,3 +501,70 @@ func (k Keeper) collectIncentives(ctx sdk.Context, poolId uint64, owner sdk.AccA | |||||||
} | ||||||||
return collectedIncentives, nil | ||||||||
} | ||||||||
|
||||||||
// createIncentive creates an incentive record in state for the given pool | ||||||||
func (k Keeper) createIncentive(ctx sdk.Context, poolId uint64, sender sdk.AccAddress, incentiveDenom string, incentiveAmount sdk.Int, emissionRate sdk.Dec, startTime time.Time, minUptime time.Duration) (types.IncentiveRecord, error) { | ||||||||
pool, err := k.getPoolById(ctx, poolId) | ||||||||
if err != nil { | ||||||||
return types.IncentiveRecord{}, err | ||||||||
} | ||||||||
|
||||||||
// Ensure incentive amount is nonzero and nonnegative | ||||||||
if !incentiveAmount.IsPositive() { | ||||||||
return types.IncentiveRecord{}, types.NonPositiveIncentiveAmountError{PoolId: poolId, IncentiveAmount: incentiveAmount.ToDec()} | ||||||||
} | ||||||||
|
||||||||
// Ensure start time is >= current blocktime | ||||||||
if startTime.Before(ctx.BlockTime()) { | ||||||||
return types.IncentiveRecord{}, types.StartTimeTooEarlyError{PoolId: poolId, CurrentBlockTime: ctx.BlockTime(), StartTime: startTime} | ||||||||
} | ||||||||
|
||||||||
// Ensure emission rate is nonzero and nonnegative | ||||||||
if !emissionRate.IsPositive() { | ||||||||
return types.IncentiveRecord{}, types.NonPositiveEmissionRateError{PoolId: poolId, EmissionRate: emissionRate} | ||||||||
} | ||||||||
|
||||||||
// Ensure min uptime is one of the supported periods | ||||||||
validUptime := false | ||||||||
for _, supportedUptime := range types.SupportedUptimes { | ||||||||
if minUptime == supportedUptime { | ||||||||
validUptime = true | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
} | ||||||||
if !validUptime { | ||||||||
return types.IncentiveRecord{}, types.InvalidMinUptimeError{PoolId: poolId, MinUptime: minUptime, SupportedUptimes: types.SupportedUptimes} | ||||||||
} | ||||||||
|
||||||||
// Ensure sender has balance for incentive denom | ||||||||
incentiveCoin := sdk.NewCoin(incentiveDenom, incentiveAmount) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. related to earlier comments - I think having it as |
||||||||
senderHasBalance := k.bankKeeper.HasBalance(ctx, sender, incentiveCoin) | ||||||||
if !senderHasBalance { | ||||||||
return types.IncentiveRecord{}, types.IncentiveInsufficientBalanceError{PoolId: poolId, IncentiveDenom: incentiveDenom, IncentiveAmount: incentiveAmount} | ||||||||
} | ||||||||
|
||||||||
// Sync global uptime accumulators to current blocktime to ensure consistency in reward emissions | ||||||||
err = k.updateUptimeAccumulatorsToNow(ctx, poolId) | ||||||||
if err != nil { | ||||||||
return types.IncentiveRecord{}, err | ||||||||
} | ||||||||
|
||||||||
// Set up incentive record to put in state | ||||||||
incentiveRecord := types.IncentiveRecord{ | ||||||||
PoolId: poolId, | ||||||||
IncentiveDenom: incentiveDenom, | ||||||||
RemainingAmount: incentiveAmount.ToDec(), | ||||||||
EmissionRate: emissionRate, | ||||||||
StartTime: startTime, | ||||||||
MinUptime: minUptime, | ||||||||
} | ||||||||
|
||||||||
// Set incentive record in state | ||||||||
k.setIncentiveRecord(ctx, incentiveRecord) | ||||||||
|
||||||||
// Transfer tokens from sender to pool balance | ||||||||
if err := k.bankKeeper.SendCoins(ctx, sender, pool.GetAddress(), sdk.NewCoins(incentiveCoin)); err != nil { | ||||||||
return types.IncentiveRecord{}, err | ||||||||
} | ||||||||
|
||||||||
return incentiveRecord, nil | ||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a thought, why not set this as Coin instead of denom and amount? so that later down the line we can create incentives record for many Coins
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed on making this a Coin, unless it was by design for a reason I am not seeing.