-
Notifications
You must be signed in to change notification settings - Fork 601
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
(v18: feat) Volume-Split, setup gauges to split evenly #6085
Changes from 5 commits
6812b45
57a4b1a
7b330ba
58dde1a
c99cb1d
2fe6334
cad538f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,24 @@ message Gauge { | |
]; | ||
} | ||
|
||
// SplittingPolicy determines the way we want to split incentives in groupGauges | ||
enum SplittingPolicy { | ||
option (gogoproto.goproto_enum_prefix) = false; | ||
|
||
Volume = 0; | ||
Liquidity = 1; | ||
Evenly = 2; | ||
} | ||
|
||
// Gauge is an object that stores GroupGaugeId as well as internalGaugeIds. We | ||
// linked these two together so that we can distribute tokens from groupGauge to | ||
// internalGauges. | ||
message GroupGauge { | ||
uint64 group_gauge_id = 1; | ||
repeated uint64 internal_ids = 2; | ||
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. We should include a splitting policy field here as an enum, even if it currently just evenly splits 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. |
||
SplittingPolicy splitting_policy = 3; | ||
} | ||
|
||
message LockableDurationsInfo { | ||
// List of incentivised durations that gauges will pay out to | ||
repeated google.protobuf.Duration lockable_durations = 1 [ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -266,6 +266,71 @@ func (k Keeper) distributeSyntheticInternal( | |
return k.distributeInternal(ctx, gauge, sortedAndTrimmedQualifiedLocks, distrInfo) | ||
} | ||
|
||
// AllocateAcrossGauges gets all the active groupGauges and distributes tokens evenly based on the internalGauges set for that | ||
// groupGauge. After each iteration we update the groupGauge by modifying filledEpoch and distributed coins. | ||
// TODO: Replace even split by volume split once its implemented. | ||
func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { | ||
currTime := ctx.BlockTime() | ||
|
||
groupGauges, err := k.GetAllGroupGauges(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, groupGauge := range groupGauges { | ||
gauge, err := k.GetGaugeByID(ctx, groupGauge.GroupGaugeId) | ||
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. Err what are we actually getting here? Don't we already have the group gauge? 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.
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
// only allow distribution if the GroupGauge is Active | ||
if !currTime.Before(gauge.StartTime) && (gauge.IsPerpetual || gauge.FilledEpochs < gauge.NumEpochsPaidOver) { | ||
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. nit: for general readability, I think doing something like "if currTime.After(startTime) && (!gaugeIsActive bool), then Ofc feel free to ignore this if you think the current approach is more readable (hence the nit) – my thinking is just that you need to keep track of fewer things mentally when you're not in a branch 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. yup i think we can just replace this with |
||
coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch, err := k.CalcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, internalGaugeId := range groupGauge.InternalIds { | ||
err = k.AddToGaugeRewardsFromGauge(ctx, groupGauge.GroupGaugeId, coinsToDistributePerInternalGauge, internalGaugeId) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// we distribute tokens from groupGauge to internal gauge therefore update groupGauge fields | ||
// updates filledEpoch and distributedCoins | ||
k.updateGaugePostDistribute(ctx, *gauge, coinsToDistributeThisEpoch) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// CalcSplitPolicyCoins calculates tokens to split given a policy and groupGauge. | ||
func (k Keeper) CalcSplitPolicyCoins(ctx sdk.Context, policy types.SplittingPolicy, groupGauge *types.Gauge, groupGaugeObj types.GroupGauge) (sdk.Coins, sdk.Coins, error) { | ||
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. nit: this should probably be a private function |
||
// TODO: add volume split policy | ||
if policy == types.Evenly { | ||
remainCoins := groupGauge.Coins.Sub(groupGauge.DistributedCoins) | ||
|
||
var coinsDistPerInternalGauge, coinsDistThisEpoch sdk.Coins | ||
for _, coin := range remainCoins { | ||
epochDiff := groupGauge.NumEpochsPaidOver - groupGauge.FilledEpochs | ||
internalGaugeLen := len(groupGaugeObj.InternalIds) | ||
|
||
distPerEpoch := coin.Amount.Quo(sdk.NewIntFromUint64(epochDiff)) | ||
distPerGauge := distPerEpoch.Quo(sdk.NewInt(int64(internalGaugeLen))) | ||
|
||
coinsDistThisEpoch = coinsDistThisEpoch.Add(sdk.NewCoin(coin.Denom, distPerEpoch)) | ||
coinsDistPerInternalGauge = coinsDistPerInternalGauge.Add(sdk.NewCoin(coin.Denom, distPerGauge)) | ||
} | ||
|
||
return coinsDistPerInternalGauge, coinsDistThisEpoch, nil | ||
} else { | ||
return nil, nil, fmt.Errorf("GroupGauge id %d doesnot have enought coins to distribute.", &groupGauge.Id) | ||
} | ||
|
||
} | ||
|
||
// distributeInternal runs the distribution logic for a gauge, and adds the sends to | ||
// the distrInfo struct. It also updates the gauge for the distribution. | ||
// It handles any kind of gauges: | ||
|
@@ -285,6 +350,7 @@ func (k Keeper) distributeInternal( | |
totalDistrCoins := sdk.NewCoins() | ||
|
||
remainCoins := gauge.Coins.Sub(gauge.DistributedCoins) | ||
|
||
// if its a perpetual gauge, we set remaining epochs to 1. | ||
// otherwise is is a non perpetual gauge and we determine how many epoch payouts are left | ||
remainEpochs := uint64(1) | ||
|
@@ -329,7 +395,6 @@ func (k Keeper) distributeInternal( | |
// for ex: 10000uosmo to be distributed over 1day epoch will be 1000 tokens ÷ 86,400 seconds ≈ 0.01157 tokens per second (truncated) | ||
// Note: reason why we do millisecond conversion is because floats are non-deterministic. | ||
emissionRate := sdk.NewDecFromInt(remainAmountPerEpoch).QuoTruncate(sdk.NewDec(currentEpoch.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) | ||
|
||
ctx.Logger().Debug("distributeInternal, CreateIncentiveRecord NoLock gauge", "module", types.ModuleName, "gaugeId", gauge.Id, "poolId", pool.GetId(), "remainCoinPerEpoch", remainCoinPerEpoch, "height", ctx.BlockHeight()) | ||
_, err := k.clk.CreateIncentive(ctx, | ||
pool.GetId(), | ||
|
@@ -346,7 +411,6 @@ func (k Keeper) distributeInternal( | |
if err != nil { | ||
return nil, err | ||
} | ||
|
||
totalDistrCoins = totalDistrCoins.Add(remainCoinPerEpoch) | ||
} | ||
} else { | ||
|
@@ -441,6 +505,11 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er | |
ctx.Logger().Debug("distributeSyntheticInternal, gauge id %d, %d", "module", types.ModuleName, "gaugeId", gauge.Id, "height", ctx.BlockHeight()) | ||
gaugeDistributedCoins, err = k.distributeSyntheticInternal(ctx, gauge, filteredLocks, &distrInfo) | ||
} else { | ||
// Donot distribue if LockQueryType = Group, because if we distribute here we will be double distributing. | ||
stackman27 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if gauge.DistributeTo.LockQueryType == lockuptypes.ByGroup { | ||
continue | ||
} | ||
|
||
gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo) | ||
} | ||
if err != 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.
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.
We're likely to simply remove liquidity based splitting for the reasons described in #6093