From fd25476925450e963ef923e10692bbfe30ea7c43 Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Sun, 25 Feb 2024 22:32:06 -0700 Subject: [PATCH 01/10] min osmo value for distribution --- app/keepers/keepers.go | 1 + app/upgrades/v24/upgrades.go | 6 ++ app/upgrades/v24/upgrades_test.go | 8 ++ proto/osmosis/incentives/params.proto | 9 ++ x/incentives/keeper/distribute.go | 73 +++++++++++++++- x/incentives/keeper/keeper.go | 4 +- x/incentives/types/constants.go | 9 +- x/incentives/types/expected_keepers.go | 5 ++ x/incentives/types/params.go | 19 ++++- x/incentives/types/params.pb.go | 114 ++++++++++++++++++------- 10 files changed, 213 insertions(+), 35 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 1785674e804..2cc884f4d99 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -420,6 +420,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.ConcentratedLiquidityKeeper, appKeepers.PoolManagerKeeper, appKeepers.PoolIncentivesKeeper, + appKeepers.ProtoRevKeeper, ) appKeepers.ConcentratedLiquidityKeeper.SetIncentivesKeeper(appKeepers.IncentivesKeeper) appKeepers.GAMMKeeper.SetIncentivesKeeper(appKeepers.IncentivesKeeper) diff --git a/app/upgrades/v24/upgrades.go b/app/upgrades/v24/upgrades.go index 4a0bd361219..c054cdb0fe8 100644 --- a/app/upgrades/v24/upgrades.go +++ b/app/upgrades/v24/upgrades.go @@ -7,6 +7,8 @@ import ( "github.com/osmosis-labs/osmosis/v23/app/keepers" "github.com/osmosis-labs/osmosis/v23/app/upgrades" + + incentivestypes "github.com/osmosis-labs/osmosis/v23/x/incentives/types" ) func CreateUpgradeHandler( @@ -39,6 +41,10 @@ func CreateUpgradeHandler( // since we only need the pool indexed TWAPs. keepers.TwapKeeper.DeleteAllHistoricalTimeIndexedTWAPs(ctx) + // Set the new min osmo value for distribution for the incentives module. + // https://www.mintscan.io/osmosis/proposals/733 + keepers.IncentivesKeeper.SetParam(ctx, incentivestypes.KeyMinOsmoValueForDistr, incentivestypes.DefaultMinOsmoValueForDistr) + return migrations, nil } } diff --git a/app/upgrades/v24/upgrades_test.go b/app/upgrades/v24/upgrades_test.go index 978f3ac97e3..36c8980553e 100644 --- a/app/upgrades/v24/upgrades_test.go +++ b/app/upgrades/v24/upgrades_test.go @@ -16,6 +16,7 @@ import ( "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/v23/app/apptesting" + incentivestypes "github.com/osmosis-labs/osmosis/v23/x/incentives/types" protorevtypes "github.com/osmosis-labs/osmosis/v23/x/protorev/types" "github.com/osmosis-labs/osmosis/v23/x/twap/types" twaptypes "github.com/osmosis-labs/osmosis/v23/x/twap/types" @@ -131,6 +132,13 @@ func (s *UpgradeTestSuite) TestUpgrade() { oldBaseDenoms, err = s.App.ProtoRevKeeper.DeprecatedGetAllBaseDenoms(s.Ctx) s.Require().NoError(err) s.Require().Empty(oldBaseDenoms) + + // INCENTIVES Tests + // + + // Check that the new min osmo value for distribution has been set + params := s.App.IncentivesKeeper.GetParams(s.Ctx) + s.Require().Equal(incentivestypes.DefaultMinOsmoValueForDistr, params.MinOsmoValueForDistribution) } func dummyUpgrade(s *UpgradeTestSuite) { diff --git a/proto/osmosis/incentives/params.proto b/proto/osmosis/incentives/params.proto index 62d7629127f..df90eec7f57 100644 --- a/proto/osmosis/incentives/params.proto +++ b/proto/osmosis/incentives/params.proto @@ -44,4 +44,13 @@ message Params { (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"internal_uptime\"" ]; + // min_osmo_value_for_distribution is the minimum amount a token must be worth + // in terms of OSMO to be eligible for distribution. If the token is worth + // less than this amount, it will not be distributed and is forfeited to the + // remaining distributees that are eligible. + string min_osmo_value_for_distribution = 5 [ + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.moretags) = "yaml:\"min_osmo_value_for_distribution\"", + (gogoproto.nullable) = false + ]; } diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index 7949fcc87a2..dc7792f58b7 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -23,8 +23,15 @@ import ( var ( millisecondsInSecDec = osmomath.NewDec(1000) + zeroInt = osmomath.ZeroInt() ) +// DistributionValueCache is a cache for when we calculate the minimum value +// an underlying token must be to be distributed. +type DistributionValueCache struct { + denomToMinValueMap map[string]osmomath.Int +} + // AllocateAcrossGauges for every gauge in the input, it updates the weights according to the splitting // policy and allocates the coins to the underlying gauges per the updated weights. // Note, every group is associated with a group gauge. The distribution to regular gauges @@ -454,7 +461,7 @@ func (k Keeper) syncGroupWeights(ctx sdk.Context, group types.Group) error { // calculateGroupWeights calculates the updated weights of the group records based on the pool volumes. // It returns the updated group and an error if any. It does not mutate the passed in object. func (k Keeper) calculateGroupWeights(ctx sdk.Context, group types.Group) (types.Group, error) { - totalWeight := sdk.ZeroInt() + totalWeight := zeroInt // We operate on a deep copy of the given group because we expect to handle specific errors quietly // and want to avoid the scenario where the original group gauge is partially mutated in such cases. @@ -615,6 +622,20 @@ func (k Keeper) distributeInternal( ) (sdk.Coins, error) { totalDistrCoins := sdk.NewCoins() + // Retrieve the min osmo value for distribution. + // If any distribution amount is valued less than what the param is set, it will be skipped. + minOsmoValueForDistr := k.GetParams(ctx).MinOsmoValueForDistribution + osmoDenom, err := k.tk.GetBaseDenom(ctx) + if err != nil { + return nil, err + } + + // Set up the cache for the distribution. + // This way we don't need to calculate what the min value needs to be f + cache := DistributionValueCache{ + denomToMinValueMap: make(map[string]osmomath.Int), + } + remainCoins := gauge.Coins.Sub(gauge.DistributedCoins...) // if its a perpetual gauge, we set remaining epochs to 1. @@ -722,6 +743,54 @@ func (k Keeper) distributeInternal( // which is bounded to an Int. So we can safely skip this. amtIntBi.Quo(amtIntBi, lockSumTimesRemainingEpochsBi) + + // Determine if the value to distribute is worth enough in OSMO to be distributed. + if coin.Denom == osmoDenom { + // If the denom is OSMO, no transformation is needed. + if amtInt.LT(minOsmoValueForDistr) { + continue + } + } else { + // If the denom is not OSMO, we need to transform the underlying to OSMO. + // Check if the denom exists in the cached values + value, ok := cache.denomToMinValueMap[coin.Denom] + if !ok { + // Cache miss, figure out the value and add it to the cache + poolId, err := k.prk.GetPoolForDenomPairNoOrder(ctx, osmoDenom, coin.Denom) + if err != nil { + // If the pool denom pair pool route does not exist in protorev, we add a zero value to cache to avoid + // querying the pool again. + cache.denomToMinValueMap[coin.Denom] = zeroInt + continue + } + swapModule, pool, err := k.pmk.GetPoolModuleAndPool(ctx, poolId) + if err != nil { + return nil, err + } + minOsmoCoin := sdk.Coin{Denom: osmoDenom, Amount: minOsmoValueForDistr} + + minTokenRequiredForDistr, err := swapModule.CalcOutAmtGivenIn(ctx, pool, minOsmoCoin, coin.Denom, sdk.ZeroDec()) + if err != nil { + return nil, err + } + + // Add min token required for distribution to the cache + cache.denomToMinValueMap[coin.Denom] = minTokenRequiredForDistr.Amount + + // Check if the value is worth enough in the token to be distributed. + if coin.Amount.LT(minTokenRequiredForDistr.Amount) { + continue + } + } else { + // Cache hit, use the value + + // Check if the underlying is worth enough in the token to be distributed. + if coin.Amount.LT(value) { + continue + } + } + } + if amtInt.Sign() == 1 { newlyDistributedCoin := sdk.Coin{Denom: coin.Denom, Amount: amtInt} distrCoins = distrCoins.Add(newlyDistributedCoin) @@ -750,7 +819,7 @@ func (k Keeper) distributeInternal( } } - err := k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins) + err = k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins) return totalDistrCoins, err } diff --git a/x/incentives/keeper/keeper.go b/x/incentives/keeper/keeper.go index e96053084dd..27db39df642 100644 --- a/x/incentives/keeper/keeper.go +++ b/x/incentives/keeper/keeper.go @@ -28,10 +28,11 @@ type Keeper struct { clk types.ConcentratedLiquidityKeeper pmk types.PoolManagerKeeper pik types.PoolIncentiveKeeper + prk types.ProtorevKeeper } // NewKeeper returns a new instance of the incentive module keeper struct. -func NewKeeper(storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, lk types.LockupKeeper, ek types.EpochKeeper, ck types.CommunityPoolKeeper, txfk types.TxFeesKeeper, clk types.ConcentratedLiquidityKeeper, pmk types.PoolManagerKeeper, pik types.PoolIncentiveKeeper) *Keeper { +func NewKeeper(storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, lk types.LockupKeeper, ek types.EpochKeeper, ck types.CommunityPoolKeeper, txfk types.TxFeesKeeper, clk types.ConcentratedLiquidityKeeper, pmk types.PoolManagerKeeper, pik types.PoolIncentiveKeeper, prk types.ProtorevKeeper) *Keeper { if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } @@ -48,6 +49,7 @@ func NewKeeper(storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, ak tk: txfk, pmk: pmk, clk: clk, + prk: prk, } } diff --git a/x/incentives/types/constants.go b/x/incentives/types/constants.go index 677071008c5..974a4be0bb7 100644 --- a/x/incentives/types/constants.go +++ b/x/incentives/types/constants.go @@ -1,6 +1,10 @@ package types -import time "time" +import ( + time "time" + + sdkmath "cosmossdk.io/math" +) var ( BaseGasFeeForCreateGauge = 10_000 @@ -12,5 +16,6 @@ var ( // PerpetualNumEpochsPaidOver is the number of epochs that must be given // for a gauge to be perpetual. For any other number of epochs // other than zero, the gauge is non-perpetual. Zero is invalid. - PerpetualNumEpochsPaidOver = uint64(0) + PerpetualNumEpochsPaidOver = uint64(0) + DefaultMinOsmoValueForDistr = sdkmath.NewInt(10000) // 0.01 ) diff --git a/x/incentives/types/expected_keepers.go b/x/incentives/types/expected_keepers.go index dcc88a52dc0..b1676b2ad81 100644 --- a/x/incentives/types/expected_keepers.go +++ b/x/incentives/types/expected_keepers.go @@ -71,4 +71,9 @@ type GAMMKeeper interface { type PoolManagerKeeper interface { GetPool(ctx sdk.Context, poolId uint64) (poolmanagertypes.PoolI, error) GetOsmoVolumeForPool(ctx sdk.Context, poolId uint64) osmomath.Int + GetPoolModuleAndPool(ctx sdk.Context, poolId uint64) (swapModule poolmanagertypes.PoolModuleI, pool poolmanagertypes.PoolI, err error) +} + +type ProtorevKeeper interface { + GetPoolForDenomPairNoOrder(ctx sdk.Context, denom1, denom2 string) (uint64, error) } diff --git a/x/incentives/types/params.go b/x/incentives/types/params.go index c1915ad5d54..3cc0f458cda 100644 --- a/x/incentives/types/params.go +++ b/x/incentives/types/params.go @@ -10,6 +10,7 @@ import ( cltypes "github.com/osmosis-labs/osmosis/v23/x/concentrated-liquidity/types" epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types" + sdkmath "cosmossdk.io/math" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -19,6 +20,7 @@ var ( KeyGroupCreationFee = []byte("GroupCreationFee") KeyCreatorWhitelist = []byte("CreatorWhitelist") KeyInternalUptime = []byte("InternalUptime") + KeyMinOsmoValueForDistr = []byte("MinOsmoValueForDistr") // 100 OSMO DefaultGroupCreationFee = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))) @@ -30,12 +32,13 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewParams takes an epoch distribution identifier and group creation fee, then returns an incentives Params struct. -func NewParams(distrEpochIdentifier string, groupCreationFee sdk.Coins, internalUptime time.Duration) Params { +func NewParams(distrEpochIdentifier string, groupCreationFee sdk.Coins, internalUptime time.Duration, minOsmoValueForDistr sdkmath.Int) Params { return Params{ DistrEpochIdentifier: distrEpochIdentifier, GroupCreationFee: groupCreationFee, UnrestrictedCreatorWhitelist: []string{}, InternalUptime: internalUptime, + MinOsmoValueForDistribution: minOsmoValueForDistr, } } @@ -46,6 +49,7 @@ func DefaultParams() Params { GroupCreationFee: DefaultGroupCreationFee, UnrestrictedCreatorWhitelist: []string{}, InternalUptime: DefaultConcentratedUptime, + MinOsmoValueForDistribution: DefaultMinOsmoValueForDistr, } } @@ -67,6 +71,10 @@ func (p Params) Validate() error { return err } + if err := ValidateMinOsmoValueForDistr(p.MinOsmoValueForDistribution); err != nil { + return err + } + return nil } @@ -109,6 +117,14 @@ func ValidateInternalUptime(i interface{}) error { return nil } +func ValidateMinOsmoValueForDistr(i interface{}) error { + _, ok := i.(sdkmath.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + return nil +} + // ParamSetPairs takes the parameter struct and associates the paramsubspace key and field of the parameters as a KVStore. func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ @@ -116,5 +132,6 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyGroupCreationFee, &p.GroupCreationFee, ValidateGroupCreaionFee), paramtypes.NewParamSetPair(KeyCreatorWhitelist, &p.UnrestrictedCreatorWhitelist, osmoutils.ValidateAddressList), paramtypes.NewParamSetPair(KeyInternalUptime, &p.InternalUptime, ValidateInternalUptime), + paramtypes.NewParamSetPair(KeyMinOsmoValueForDistr, &p.MinOsmoValueForDistribution, ValidateMinOsmoValueForDistr), } } diff --git a/x/incentives/types/params.pb.go b/x/incentives/types/params.pb.go index 4fcf17e42fa..1427b26affb 100644 --- a/x/incentives/types/params.pb.go +++ b/x/incentives/types/params.pb.go @@ -4,6 +4,7 @@ package types import ( + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" @@ -54,6 +55,11 @@ type Params struct { // the uptime of those incentives as well (i.e. distributions through volume // splitting incentives will use this uptime). InternalUptime time.Duration `protobuf:"bytes,4,opt,name=internal_uptime,json=internalUptime,proto3,stdduration" json:"internal_uptime" yaml:"internal_uptime"` + // min_osmo_value_for_distribution is the minimum amount a token must be worth + // in terms of OSMO to be eligible for distribution. If the token is worth + // less than this amount, it will not be distributed and is forfeited to the + // remaining distributees that are eligible. + MinOsmoValueForDistribution cosmossdk_io_math.Int `protobuf:"bytes,5,opt,name=min_osmo_value_for_distribution,json=minOsmoValueForDistribution,proto3,customtype=cosmossdk.io/math.Int" json:"min_osmo_value_for_distribution" yaml:"min_osmo_value_for_distribution"` } func (m *Params) Reset() { *m = Params{} } @@ -124,35 +130,39 @@ func init() { func init() { proto.RegisterFile("osmosis/incentives/params.proto", fileDescriptor_1cc8b460d089f845) } var fileDescriptor_1cc8b460d089f845 = []byte{ - // 433 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xc1, 0x8a, 0xd4, 0x40, - 0x10, 0x9d, 0x38, 0xb2, 0xb0, 0x11, 0x54, 0xc2, 0xb2, 0x8c, 0x8b, 0x76, 0xc6, 0x80, 0x30, 0x1e, - 0xb6, 0xdb, 0xdd, 0x05, 0x0f, 0x1e, 0x33, 0x2a, 0x78, 0x5b, 0x06, 0x64, 0xc1, 0x4b, 0xe8, 0x24, - 0x95, 0x4c, 0x63, 0x92, 0x0a, 0xdd, 0x9d, 0xd1, 0xf9, 0x0b, 0x8f, 0x7e, 0x83, 0x77, 0xff, 0x61, - 0x8f, 0x7b, 0xf4, 0x94, 0x95, 0x99, 0x3f, 0x98, 0x2f, 0x90, 0x74, 0x27, 0x3a, 0x88, 0x78, 0x4a, - 0xfa, 0xbd, 0x57, 0xbc, 0x7a, 0x55, 0xe5, 0xfa, 0xa8, 0x4a, 0x54, 0x42, 0x31, 0x51, 0x25, 0x50, - 0x69, 0xb1, 0x02, 0xc5, 0x6a, 0x2e, 0x79, 0xa9, 0x68, 0x2d, 0x51, 0xa3, 0xe7, 0xf5, 0x02, 0xfa, - 0x47, 0x70, 0x72, 0x94, 0x63, 0x8e, 0x86, 0x66, 0xdd, 0x9f, 0x55, 0x9e, 0x90, 0xc4, 0x48, 0x59, - 0xcc, 0x15, 0xb0, 0xd5, 0x59, 0x0c, 0x9a, 0x9f, 0xb1, 0x04, 0x45, 0x35, 0xf0, 0x39, 0x62, 0x5e, - 0x00, 0x33, 0xaf, 0xb8, 0xc9, 0x58, 0xda, 0x48, 0xae, 0x05, 0xf6, 0x7c, 0xf0, 0x7d, 0xec, 0x1e, - 0x5c, 0x1a, 0x6b, 0xef, 0xca, 0x3d, 0x4e, 0x85, 0xd2, 0x32, 0x82, 0x1a, 0x93, 0x65, 0x24, 0xd2, - 0xce, 0x39, 0x13, 0x20, 0x27, 0xce, 0xd4, 0x99, 0x1d, 0x86, 0x4f, 0x77, 0xad, 0xff, 0x64, 0xcd, - 0xcb, 0xe2, 0x55, 0xf0, 0x6f, 0x5d, 0xb0, 0x38, 0x32, 0xc4, 0x9b, 0x0e, 0x7f, 0xf7, 0x1b, 0xf6, - 0xd6, 0xae, 0x97, 0x4b, 0x6c, 0xea, 0x28, 0x91, 0x60, 0xbc, 0xa3, 0x0c, 0x60, 0x72, 0x67, 0x3a, - 0x9e, 0xdd, 0x3b, 0x7f, 0x44, 0x6d, 0x00, 0xda, 0x05, 0xa0, 0x7d, 0x00, 0x3a, 0x47, 0x51, 0x85, - 0x2f, 0xae, 0x5b, 0x7f, 0xf4, 0xed, 0xd6, 0x9f, 0xe5, 0x42, 0x2f, 0x9b, 0x98, 0x26, 0x58, 0xb2, - 0x3e, 0xad, 0xfd, 0x9c, 0xaa, 0xf4, 0x23, 0xd3, 0xeb, 0x1a, 0x94, 0x29, 0x50, 0x8b, 0x87, 0xc6, - 0x66, 0xde, 0xbb, 0xbc, 0x05, 0xf0, 0xd0, 0x25, 0x4d, 0x25, 0x41, 0x69, 0x29, 0x12, 0x0d, 0xa9, - 0xed, 0x00, 0x65, 0xf4, 0x69, 0x29, 0x34, 0x14, 0x42, 0xe9, 0xc9, 0x78, 0x3a, 0x9e, 0x1d, 0x86, - 0xcf, 0x77, 0xad, 0xff, 0xcc, 0x66, 0xfb, 0xbf, 0x3e, 0x58, 0x3c, 0xde, 0x17, 0xcc, 0x2d, 0x7f, - 0x35, 0xd0, 0x5e, 0xe6, 0x3e, 0x10, 0x95, 0x06, 0x59, 0xf1, 0x22, 0x6a, 0x6a, 0x2d, 0x4a, 0x98, - 0xdc, 0x9d, 0x3a, 0x26, 0xa8, 0xdd, 0x04, 0x1d, 0x36, 0x41, 0x5f, 0xf7, 0x9b, 0x08, 0x83, 0x2e, - 0xe8, 0xae, 0xf5, 0x8f, 0x6d, 0x03, 0x7f, 0xd5, 0x07, 0x5f, 0x6f, 0x7d, 0x67, 0x71, 0x7f, 0x40, - 0xdf, 0x1b, 0x30, 0xbc, 0xbc, 0xde, 0x10, 0xe7, 0x66, 0x43, 0x9c, 0x9f, 0x1b, 0xe2, 0x7c, 0xd9, - 0x92, 0xd1, 0xcd, 0x96, 0x8c, 0x7e, 0x6c, 0xc9, 0xe8, 0xc3, 0xcb, 0xbd, 0x71, 0xf5, 0x67, 0x74, - 0x5a, 0xf0, 0x58, 0x0d, 0x0f, 0xb6, 0x3a, 0xbf, 0x60, 0x9f, 0xf7, 0x4f, 0xcf, 0x8c, 0x30, 0x3e, - 0x30, 0x8d, 0x5d, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x38, 0x06, 0x4f, 0x9d, 0x02, 0x00, - 0x00, + // 508 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0xc1, 0x6a, 0xd4, 0x40, + 0x18, 0xde, 0xb8, 0xb5, 0xd0, 0x08, 0x2a, 0xa1, 0x96, 0xb5, 0x6a, 0xb2, 0x06, 0x94, 0xf5, 0xd0, + 0x19, 0xdb, 0x82, 0x07, 0x8f, 0xbb, 0xb5, 0xd2, 0x93, 0x65, 0x41, 0x0b, 0x5e, 0x86, 0x49, 0x32, + 0x9b, 0x1d, 0x9a, 0xcc, 0x1f, 0x66, 0x26, 0xab, 0xfb, 0x10, 0x82, 0x47, 0x9f, 0xc1, 0xf7, 0x10, + 0x7a, 0xec, 0x51, 0x3c, 0xa4, 0xb2, 0xfb, 0x06, 0xfb, 0x04, 0x92, 0x99, 0x44, 0x17, 0x11, 0x7b, + 0x4a, 0xe6, 0xff, 0xbe, 0xf9, 0xbf, 0xff, 0xfb, 0xbf, 0xc4, 0x0d, 0x40, 0xe5, 0xa0, 0xb8, 0xc2, + 0x5c, 0xc4, 0x4c, 0x68, 0x3e, 0x63, 0x0a, 0x17, 0x54, 0xd2, 0x5c, 0xa1, 0x42, 0x82, 0x06, 0xcf, + 0x6b, 0x08, 0xe8, 0x0f, 0x61, 0x77, 0x3b, 0x85, 0x14, 0x0c, 0x8c, 0xeb, 0x37, 0xcb, 0xdc, 0xf5, + 0x63, 0x43, 0xc5, 0x11, 0x55, 0x0c, 0xcf, 0xf6, 0x23, 0xa6, 0xe9, 0x3e, 0x8e, 0x81, 0x8b, 0x16, + 0x4f, 0x01, 0xd2, 0x8c, 0x61, 0x73, 0x8a, 0xca, 0x09, 0x4e, 0x4a, 0x49, 0x35, 0x87, 0x06, 0x0f, + 0xbf, 0x6d, 0xb8, 0x9b, 0xa7, 0x46, 0xda, 0x3b, 0x73, 0x77, 0x12, 0xae, 0xb4, 0x24, 0xac, 0x80, + 0x78, 0x4a, 0x78, 0x52, 0x2b, 0x4f, 0x38, 0x93, 0x3d, 0xa7, 0xef, 0x0c, 0xb6, 0x86, 0x8f, 0x57, + 0x55, 0xf0, 0x68, 0x4e, 0xf3, 0xec, 0x65, 0xf8, 0x6f, 0x5e, 0x38, 0xde, 0x36, 0xc0, 0xab, 0xba, + 0x7e, 0xf2, 0xbb, 0xec, 0xcd, 0x5d, 0x2f, 0x95, 0x50, 0x16, 0x24, 0x96, 0xcc, 0x68, 0x93, 0x09, + 0x63, 0xbd, 0x1b, 0xfd, 0xee, 0xe0, 0xd6, 0xc1, 0x7d, 0x64, 0x0d, 0xa0, 0xda, 0x00, 0x6a, 0x0c, + 0xa0, 0x11, 0x70, 0x31, 0x7c, 0x7e, 0x51, 0x05, 0x9d, 0xaf, 0x57, 0xc1, 0x20, 0xe5, 0x7a, 0x5a, + 0x46, 0x28, 0x86, 0x1c, 0x37, 0x6e, 0xed, 0x63, 0x4f, 0x25, 0xe7, 0x58, 0xcf, 0x0b, 0xa6, 0xcc, + 0x05, 0x35, 0xbe, 0x6b, 0x64, 0x46, 0x8d, 0xca, 0x31, 0x63, 0x1e, 0xb8, 0x7e, 0x29, 0x24, 0x53, + 0x5a, 0xf2, 0x58, 0xb3, 0xc4, 0x4e, 0x00, 0x92, 0x7c, 0x98, 0x72, 0xcd, 0x32, 0xae, 0x74, 0xaf, + 0xdb, 0xef, 0x0e, 0xb6, 0x86, 0xcf, 0x56, 0x55, 0xf0, 0xc4, 0x7a, 0xfb, 0x3f, 0x3f, 0x1c, 0x3f, + 0x5c, 0x27, 0x8c, 0x2c, 0x7e, 0xd6, 0xc2, 0xde, 0xc4, 0xbd, 0xc3, 0x85, 0x66, 0x52, 0xd0, 0x8c, + 0x94, 0x85, 0xe6, 0x39, 0xeb, 0x6d, 0xf4, 0x1d, 0x63, 0xd4, 0x26, 0x81, 0xda, 0x24, 0xd0, 0x51, + 0x93, 0xc4, 0x30, 0xac, 0x8d, 0xae, 0xaa, 0x60, 0xc7, 0x0e, 0xf0, 0xd7, 0xfd, 0xf0, 0xcb, 0x55, + 0xe0, 0x8c, 0x6f, 0xb7, 0xd5, 0xb7, 0xa6, 0xe8, 0x7d, 0x72, 0xdc, 0x20, 0xe7, 0x82, 0xd4, 0x8b, + 0x20, 0x33, 0x9a, 0x95, 0x8c, 0x4c, 0x40, 0x12, 0xb3, 0x7f, 0x1e, 0x95, 0x75, 0xdf, 0xde, 0x4d, + 0x13, 0xdb, 0xeb, 0xba, 0xfb, 0x8f, 0x2a, 0xb8, 0x67, 0x97, 0xa6, 0x92, 0x73, 0xc4, 0x01, 0xe7, + 0x54, 0x4f, 0xd1, 0x89, 0xd0, 0xab, 0x2a, 0x78, 0x6a, 0x65, 0xaf, 0xe9, 0x16, 0x8e, 0x1f, 0xe4, + 0x5c, 0xbc, 0x51, 0x39, 0xbc, 0xab, 0xf1, 0x63, 0x90, 0x47, 0x6b, 0xe8, 0xf0, 0xf4, 0x62, 0xe1, + 0x3b, 0x97, 0x0b, 0xdf, 0xf9, 0xb9, 0xf0, 0x9d, 0xcf, 0x4b, 0xbf, 0x73, 0xb9, 0xf4, 0x3b, 0xdf, + 0x97, 0x7e, 0xe7, 0xfd, 0x8b, 0xb5, 0xf8, 0x9a, 0xcf, 0x7a, 0x2f, 0xa3, 0x91, 0x6a, 0x0f, 0x78, + 0x76, 0x70, 0x88, 0x3f, 0xae, 0xff, 0x0a, 0x26, 0xd2, 0x68, 0xd3, 0x2c, 0xea, 0xf0, 0x57, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x2f, 0x33, 0x33, 0xc6, 0x2d, 0x03, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -175,6 +185,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.MinOsmoValueForDistribution.Size() + i -= size + if _, err := m.MinOsmoValueForDistribution.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.InternalUptime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InternalUptime):]) if err1 != nil { return 0, err1 @@ -251,6 +271,8 @@ func (m *Params) Size() (n int) { } l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InternalUptime) n += 1 + l + sovParams(uint64(l)) + l = m.MinOsmoValueForDistribution.Size() + n += 1 + l + sovParams(uint64(l)) return n } @@ -420,6 +442,40 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinOsmoValueForDistribution", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinOsmoValueForDistribution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From b5e89a2832b04d0a850fb48dff2041071758f187 Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Sun, 25 Feb 2024 22:36:31 -0700 Subject: [PATCH 02/10] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34e2fbbe3ae..ce7941fcf67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#7555](https://github.com/osmosis-labs/osmosis/pull/7555) Refactor taker fees, distribute via a single module account, track once at epoch * [#7562](https://github.com/osmosis-labs/osmosis/pull/7562) Speedup Protorev estimation logic by removing unnecessary taker fee simulations. * [#7595](https://github.com/osmosis-labs/osmosis/pull/7595) Fix cosmwasm pool model code ID migration. +* [#7615](https://github.com/osmosis-labs/osmosis/pull/7615) Min OSMO value of underlying for epoch distribution. ### State Compatible From 5d998dae768beccdbd79f270d4b062e2df7ecccf Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 26 Feb 2024 10:22:02 -0700 Subject: [PATCH 03/10] test fixes --- x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go | 5 ++++- x/incentives/keeper/distribute_test.go | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go b/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go index d311a0335ce..6772b2c7144 100644 --- a/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go +++ b/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go @@ -50,6 +50,9 @@ func (s *TransmuterSuite) TestFunctionalTransmuter() { expectedDenomSuffix = "/transmuter/poolshare" ) + // Set base denom + err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, uosmo) + // Create Transmuter pool transmuter := s.PrepareCosmWasmPool() @@ -77,7 +80,7 @@ func (s *TransmuterSuite) TestFunctionalTransmuter() { // Lock shares shareCoins := sdk.NewCoins(shareCoin) lockDuration := time.Hour - _, err := s.App.LockupKeeper.CreateLock(s.Ctx, s.TestAccs[0], shareCoins, lockDuration) + _, err = s.App.LockupKeeper.CreateLock(s.Ctx, s.TestAccs[0], shareCoins, lockDuration) s.Require().NoError(err) // Create gauge diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index 3de94893066..aaf0f7f3e23 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -215,6 +215,12 @@ func (s *KeeperTestSuite) TestDistribute() { } for _, tc := range tests { s.SetupTest() + + // set the base denom and min value for distribution + err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, defaultRewardDenom) + s.Require().NoError(err) + s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinOsmoValueForDistr, sdk.NewInt(1000)) + // setup gauges and the locks defined in the above tests, then distribute to them gauges := s.SetupGauges(tc.gauges, defaultLPDenom) addrs := s.SetupUserLocks(tc.users) @@ -224,7 +230,7 @@ func (s *KeeperTestSuite) TestDistribute() { s.SetupChangeRewardReceiver(tc.changeRewardReceiver, addrs) } - _, err := s.App.IncentivesKeeper.Distribute(s.Ctx, gauges) + _, err = s.App.IncentivesKeeper.Distribute(s.Ctx, gauges) s.Require().NoError(err) // check expected rewards against actual rewards received for i, addr := range addrs { From ccf5a4a4af5c161aa1413991c3b60fa398bad4b7 Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 26 Feb 2024 13:15:26 -0700 Subject: [PATCH 04/10] update tests and add fixes shown from tests --- x/incentives/keeper/distribute.go | 35 +++--- x/incentives/keeper/distribute_test.go | 148 +++++++++++++++++++++++-- x/incentives/keeper/suite_test.go | 26 +++-- 3 files changed, 178 insertions(+), 31 deletions(-) diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index dc7792f58b7..34f260463e4 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -395,7 +395,7 @@ func (k Keeper) doDistributionSends(ctx sdk.Context, distrs *distributionInfo) e // the distrInfo struct. It also updates the gauge for the distribution. // locks is expected to be the correct set of lock recipients for this gauge. func (k Keeper) distributeSyntheticInternal( - ctx sdk.Context, gauge types.Gauge, locks []*lockuptypes.PeriodLock, distrInfo *distributionInfo, + ctx sdk.Context, gauge types.Gauge, locks []*lockuptypes.PeriodLock, distrInfo *distributionInfo, minDistrValueCache *DistributionValueCache, ) (sdk.Coins, error) { qualifiedLocks := k.lk.GetLocksLongerThanDurationDenom(ctx, gauge.DistributeTo.Denom, gauge.DistributeTo.Duration) @@ -432,7 +432,7 @@ func (k Keeper) distributeSyntheticInternal( sortedAndTrimmedQualifiedLocks[v.index] = &v.lock } - return k.distributeInternal(ctx, gauge, sortedAndTrimmedQualifiedLocks, distrInfo) + return k.distributeInternal(ctx, gauge, sortedAndTrimmedQualifiedLocks, distrInfo, minDistrValueCache) } // syncGroupWeights updates the individual and total weights of the group records based on the splitting policy. @@ -618,7 +618,7 @@ func (k Keeper) getNoLockGaugeUptime(ctx sdk.Context, gauge types.Gauge, poolId // // CONTRACT: gauge passed in as argument must be an active gauge. func (k Keeper) distributeInternal( - ctx sdk.Context, gauge types.Gauge, locks []*lockuptypes.PeriodLock, distrInfo *distributionInfo, + ctx sdk.Context, gauge types.Gauge, locks []*lockuptypes.PeriodLock, distrInfo *distributionInfo, minDistrValueCache *DistributionValueCache, ) (sdk.Coins, error) { totalDistrCoins := sdk.NewCoins() @@ -630,12 +630,6 @@ func (k Keeper) distributeInternal( return nil, err } - // Set up the cache for the distribution. - // This way we don't need to calculate what the min value needs to be f - cache := DistributionValueCache{ - denomToMinValueMap: make(map[string]osmomath.Int), - } - remainCoins := gauge.Coins.Sub(gauge.DistributedCoins...) // if its a perpetual gauge, we set remaining epochs to 1. @@ -753,14 +747,14 @@ func (k Keeper) distributeInternal( } else { // If the denom is not OSMO, we need to transform the underlying to OSMO. // Check if the denom exists in the cached values - value, ok := cache.denomToMinValueMap[coin.Denom] + value, ok := minDistrValueCache.denomToMinValueMap[coin.Denom] if !ok { // Cache miss, figure out the value and add it to the cache poolId, err := k.prk.GetPoolForDenomPairNoOrder(ctx, osmoDenom, coin.Denom) if err != nil { // If the pool denom pair pool route does not exist in protorev, we add a zero value to cache to avoid // querying the pool again. - cache.denomToMinValueMap[coin.Denom] = zeroInt + minDistrValueCache.denomToMinValueMap[coin.Denom] = zeroInt continue } swapModule, pool, err := k.pmk.GetPoolModuleAndPool(ctx, poolId) @@ -775,17 +769,18 @@ func (k Keeper) distributeInternal( } // Add min token required for distribution to the cache - cache.denomToMinValueMap[coin.Denom] = minTokenRequiredForDistr.Amount + minDistrValueCache.denomToMinValueMap[coin.Denom] = minTokenRequiredForDistr.Amount // Check if the value is worth enough in the token to be distributed. - if coin.Amount.LT(minTokenRequiredForDistr.Amount) { + if amtInt.LT(minTokenRequiredForDistr.Amount) { + // The value is not worth enough, continue continue } } else { // Cache hit, use the value // Check if the underlying is worth enough in the token to be distributed. - if coin.Amount.LT(value) { + if amtInt.LT(value) || value.IsZero() { continue } } @@ -927,6 +922,14 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er totalDistributedCoins := sdk.NewCoins() scratchSlice := make([]*lockuptypes.PeriodLock, 0, 50000) + // Instead of re-fetching the minimum value an underlying token must be to meet the minimum + // requirement for distribution, we cache the values here. + // While this isn't precise as it doesn't account for price impact, it is good enough for the sole + // purpose fo determining if we should distribute the token or not. + minDistrValueCache := &DistributionValueCache{ + denomToMinValueMap: make(map[string]osmomath.Int), + } + for _, gauge := range gauges { var gaugeDistributedCoins sdk.Coins filteredLocks := k.getDistributeToBaseLocks(ctx, gauge, locksByDenomCache, &scratchSlice) @@ -934,14 +937,14 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er var err error if lockuptypes.IsSyntheticDenom(gauge.DistributeTo.Denom) { 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) + gaugeDistributedCoins, err = k.distributeSyntheticInternal(ctx, gauge, filteredLocks, &distrInfo, minDistrValueCache) } else { // Do not distribute if LockQueryType = Group, because if we distribute here we will be double distributing. if gauge.DistributeTo.LockQueryType == lockuptypes.ByGroup { continue } - gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo) + gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo, minDistrValueCache) } if err != nil { return nil, err diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index aaf0f7f3e23..ffca2d5f3eb 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "strings" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -87,16 +86,23 @@ type GroupCreationFields struct { // TestDistribute tests that when the distribute command is executed on a provided gauge // that the correct amount of rewards is sent to the correct lock owners. func (s *KeeperTestSuite) TestDistribute() { + nonBaseDenom := "bar" defaultGauge := perpGaugeDesc{ lockDenom: defaultLPDenom, lockDuration: defaultLockDuration, rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)}, } + defaultGaugeNonBaseDenom := defaultGauge + defaultGaugeNonBaseDenom.rewardAmount = sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 3000)} + doubleLengthGauge := perpGaugeDesc{ lockDenom: defaultLPDenom, lockDuration: 2 * defaultLockDuration, rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)}, } + doubleLengthGaugeNonBaseDenom := doubleLengthGauge + doubleLengthGaugeNonBaseDenom.rewardAmount = sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 3000)} + noRewardGauge := perpGaugeDesc{ lockDenom: defaultLPDenom, lockDuration: defaultLockDuration, @@ -104,13 +110,17 @@ func (s *KeeperTestSuite) TestDistribute() { } noRewardCoins := sdk.Coins{} oneKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000)} + oneKRewardCoinsNonBaseDenom := sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 1000)} twoKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 2000)} threeKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)} fiveKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 5000)} + fiveKRewardCoinsNonBaseDenom := sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 5000)} + fiveKFourHundredRewardCoinsNonBaseDenom := sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 5400)} tests := []struct { name string users []userLocks gauges []perpGaugeDesc + poolCoins sdk.Coins changeRewardReceiver []changeRewardReceiver expectedRewards []sdk.Coins }{ @@ -212,6 +222,50 @@ func (s *KeeperTestSuite) TestDistribute() { }, expectedRewards: []sdk.Coins{fiveKRewardCoins, oneKRewardCoins}, }, + // Non base denom rewards test, sufficient rewards to distribute all. + // gauge 1 gives 3k coins. three locks, all eligible. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + // 1k should to oneLockupUser and 5k to twoLockupUser. + { + name: "Non base denom, sufficient rewards to distribute all users", + users: []userLocks{oneLockupUser, twoLockupUser}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGaugeNonBaseDenom}, + poolCoins: sdk.NewCoins(sdk.NewCoin(defaultRewardDenom, sdk.NewInt(10000)), sdk.NewCoin(nonBaseDenom, sdk.NewInt(10000))), // 1 bar equals 1 defaultRewardDenom + expectedRewards: []sdk.Coins{oneKRewardCoinsNonBaseDenom, fiveKRewardCoinsNonBaseDenom}, + }, + // Non base denom rewards test, insufficient rewards to distribute for some. + // gauge 1 gives 3k coins. three locks, all eligible. + // we increased the lockup of twoLockupUser so it is eligible for distribution. + // the distribution should be 600 to user 1, and 1200 + 1200 to user 2, but only the last two 1200 get distributed due to limit of 1090. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + // the distribution should be all 3000 to twoLockupUser since it is passed the 1090 distribution threshold. + { + name: "Non base denom, insufficient rewards to distribute to user 1, sufficient rewards to distribute to user 2", + users: []userLocks{oneLockupUser, twoLockupUserDoubleAmt}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGaugeNonBaseDenom}, + poolCoins: sdk.NewCoins(sdk.NewCoin(defaultRewardDenom, sdk.NewInt(10000)), sdk.NewCoin(nonBaseDenom, sdk.NewInt(12000))), // min amt for distribution is now equal to 1090bar + expectedRewards: []sdk.Coins{noRewardCoins, fiveKFourHundredRewardCoinsNonBaseDenom}, + }, + // Non base denom rewards test, insufficient rewards to distribute all locks + // gauge 1 gives 3k coins. three locks, all eligible. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + // All pending reward payouts (600, 1200, and 3000) are all below the min threshold of 4545, so no rewards are distributed. + { + name: "Non base denom, insufficient rewards to distribute to all users", + users: []userLocks{oneLockupUser, twoLockupUserDoubleAmt}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGaugeNonBaseDenom}, + poolCoins: sdk.NewCoins(sdk.NewCoin(defaultRewardDenom, sdk.NewInt(10000)), sdk.NewCoin(nonBaseDenom, sdk.NewInt(50000))), // min amt for distribution is now equal to 4545bar + expectedRewards: []sdk.Coins{noRewardCoins, noRewardCoins}, + }, + // No pool exists for the first gauge, so only the second gauge should distribute rewards. + // gauge 1 gives 3k coins. three locks, all eligible, but no pool exists to determine underlying value so no rewards are distributed. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + { + name: "Non base denom and base denom, no pool to determine non base denom value, only base denom distributes", + users: []userLocks{oneLockupUser, twoLockupUserDoubleAmt}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGauge}, + expectedRewards: []sdk.Coins{noRewardCoins, threeKRewardCoins}, + }, } for _, tc := range tests { s.SetupTest() @@ -220,6 +274,8 @@ func (s *KeeperTestSuite) TestDistribute() { err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, defaultRewardDenom) s.Require().NoError(err) s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinOsmoValueForDistr, sdk.NewInt(1000)) + baseDenom, err := s.App.TxFeesKeeper.GetBaseDenom(s.Ctx) + s.Require().NoError(err) // setup gauges and the locks defined in the above tests, then distribute to them gauges := s.SetupGauges(tc.gauges, defaultLPDenom) @@ -230,6 +286,12 @@ func (s *KeeperTestSuite) TestDistribute() { s.SetupChangeRewardReceiver(tc.changeRewardReceiver, addrs) } + // if test requires it, set up a pool with the baseDenom and the underlying reward denom + if tc.poolCoins != nil { + poolID := s.PrepareBalancerPoolWithCoins(tc.poolCoins...) + s.App.ProtoRevKeeper.SetPoolForDenomPair(s.Ctx, baseDenom, nonBaseDenom, poolID) + } + _, err = s.App.IncentivesKeeper.Distribute(s.Ctx, gauges) s.Require().NoError(err) // check expected rewards against actual rewards received @@ -669,16 +731,23 @@ func (s *KeeperTestSuite) TestDistribute_ExternalIncentives_NoLock() { // TestSyntheticDistribute tests that when the distribute command is executed on a provided gauge // the correct amount of rewards is sent to the correct synthetic lock owners. func (s *KeeperTestSuite) TestSyntheticDistribute() { + nonBaseDenom := "bar" defaultGauge := perpGaugeDesc{ lockDenom: defaultLPSyntheticDenom, lockDuration: defaultLockDuration, rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)}, } + defaultGaugeNonBaseDenom := defaultGauge + defaultGaugeNonBaseDenom.rewardAmount = sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 3000)} + doubleLengthGauge := perpGaugeDesc{ lockDenom: defaultLPSyntheticDenom, lockDuration: 2 * defaultLockDuration, rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)}, } + doubleLengthGaugeNonBaseDenom := doubleLengthGauge + doubleLengthGaugeNonBaseDenom.rewardAmount = sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 3000)} + noRewardGauge := perpGaugeDesc{ lockDenom: defaultLPSyntheticDenom, lockDuration: defaultLockDuration, @@ -686,12 +755,17 @@ func (s *KeeperTestSuite) TestSyntheticDistribute() { } noRewardCoins := sdk.Coins{} oneKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000)} + oneKRewardCoinsNonBaseDenom := sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 1000)} twoKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 2000)} + threeKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)} fiveKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 5000)} + fiveKRewardCoinsNonBaseDenom := sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 5000)} + fiveKFourHundredRewardCoinsNonBaseDenom := sdk.Coins{sdk.NewInt64Coin(nonBaseDenom, 5400)} tests := []struct { name string users []userLocks gauges []perpGaugeDesc + poolCoins sdk.Coins expectedRewards []sdk.Coins }{ // gauge 1 gives 3k coins. three locks, all eligible. 1k coins per lock. @@ -728,24 +802,84 @@ func (s *KeeperTestSuite) TestSyntheticDistribute() { gauges: []perpGaugeDesc{noRewardGauge, defaultGauge}, expectedRewards: []sdk.Coins{oneKRewardCoins, twoKRewardCoins}, }, + // Non base denom rewards test, sufficient rewards to distribute all. + // gauge 1 gives 3k coins. three locks, all eligible. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + // 1k should to oneLockupUser and 5k to twoLockupUser. + { + name: "Non base denom, sufficient rewards to distribute all users", + users: []userLocks{oneSyntheticLockupUser, twoSyntheticLockupUser}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGaugeNonBaseDenom}, + poolCoins: sdk.NewCoins(sdk.NewCoin(defaultRewardDenom, sdk.NewInt(10000)), sdk.NewCoin(nonBaseDenom, sdk.NewInt(10000))), // 1 bar equals 1 defaultRewardDenom + expectedRewards: []sdk.Coins{oneKRewardCoinsNonBaseDenom, fiveKRewardCoinsNonBaseDenom}, + }, + // Non base denom rewards test, insufficient rewards to distribute for some. + // gauge 1 gives 3k coins. three locks, all eligible. + // we increased the lockup of twoLockupUser so it is eligible for distribution. + // the distribution should be 600 to user 1, and 1200 + 1200 to user 2, but only the last two 1200 get distributed due to limit of 1090. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + // the distribution should be all 3000 to twoLockupUser since it is passed the 1090 distribution threshold. + { + name: "Non base denom, insufficient rewards to distribute to user 1, sufficient rewards to distribute to user 2", + users: []userLocks{oneSyntheticLockupUser, twoSyntheticLockupUserDoubleAmt}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGaugeNonBaseDenom}, + poolCoins: sdk.NewCoins(sdk.NewCoin(defaultRewardDenom, sdk.NewInt(10000)), sdk.NewCoin(nonBaseDenom, sdk.NewInt(12000))), // min amt for distribution is now equal to 1090bar + expectedRewards: []sdk.Coins{noRewardCoins, fiveKFourHundredRewardCoinsNonBaseDenom}, + }, + // Non base denom rewards test, insufficient rewards to distribute all locks + // gauge 1 gives 3k coins. three locks, all eligible. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + // All pending reward payouts (600, 1200, and 3000) are all below the min threshold of 4545, so no rewards are distributed. + { + name: "Non base denom, insufficient rewards to distribute to all users", + users: []userLocks{oneSyntheticLockupUser, twoSyntheticLockupUserDoubleAmt}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGaugeNonBaseDenom}, + poolCoins: sdk.NewCoins(sdk.NewCoin(defaultRewardDenom, sdk.NewInt(10000)), sdk.NewCoin(nonBaseDenom, sdk.NewInt(50000))), // min amt for distribution is now equal to 4545bar + expectedRewards: []sdk.Coins{noRewardCoins, noRewardCoins}, + }, + // No pool exists for the first gauge, so only the second gauge should distribute rewards. + // gauge 1 gives 3k coins. three locks, all eligible, but no pool exists to determine underlying value so no rewards are distributed. + // gauge 2 gives 3k coins. one lock, to twoLockupUser. + { + name: "Non base denom and base denom, no pool to determine non base denom value, only base denom distributes", + users: []userLocks{oneSyntheticLockupUser, twoSyntheticLockupUserDoubleAmt}, + gauges: []perpGaugeDesc{defaultGaugeNonBaseDenom, doubleLengthGauge}, + expectedRewards: []sdk.Coins{noRewardCoins, threeKRewardCoins}, + }, } for _, tc := range tests { s.SetupTest() + + // set the base denom and min value for distribution + err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, defaultRewardDenom) + s.Require().NoError(err) + s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinOsmoValueForDistr, sdk.NewInt(1000)) + baseDenom, err := s.App.TxFeesKeeper.GetBaseDenom(s.Ctx) + s.Require().NoError(err) + // setup gauges and the synthetic locks defined in the above tests, then distribute to them gauges := s.SetupGauges(tc.gauges, defaultLPSyntheticDenom) addrs := s.SetupUserSyntheticLocks(tc.users) - _, err := s.App.IncentivesKeeper.Distribute(s.Ctx, gauges) + + // if test requires it, set up a pool with the baseDenom and the underlying reward denom + if tc.poolCoins != nil { + poolID := s.PrepareBalancerPoolWithCoins(tc.poolCoins...) + s.App.ProtoRevKeeper.SetPoolForDenomPair(s.Ctx, baseDenom, nonBaseDenom, poolID) + } + + _, err = s.App.IncentivesKeeper.Distribute(s.Ctx, gauges) s.Require().NoError(err) // check expected rewards against actual rewards received for i, addr := range addrs { - var rewards string bal := s.App.BankKeeper.GetAllBalances(s.Ctx, addr) // extract the superbonding tokens from the rewards distribution - // TODO: figure out a less hacky way of doing this - if strings.Contains(bal.String(), "lptoken/superbonding,") { - rewards = strings.Split(bal.String(), "lptoken/superbonding,")[1] + rewards := sdk.Coins{} + for _, coin := range bal { + if coin.Denom != "lptoken/superbonding" { + rewards = append(rewards, coin) + } } - s.Require().Equal(tc.expectedRewards[i].String(), rewards, "test %v, person %d", tc.name, i) + s.Require().Equal(tc.expectedRewards[i].String(), rewards.String(), "test %v, person %d", tc.name, i) } } } diff --git a/x/incentives/keeper/suite_test.go b/x/incentives/keeper/suite_test.go index 9782425eacb..216aabf2d4b 100644 --- a/x/incentives/keeper/suite_test.go +++ b/x/incentives/keeper/suite_test.go @@ -12,13 +12,15 @@ import ( ) var ( - defaultLPDenom string = "lptoken" - defaultLPSyntheticDenom string = "lptoken/superbonding" - defaultLPTokens sdk.Coins = sdk.Coins{sdk.NewInt64Coin(defaultLPDenom, 10)} - defaultLPSyntheticTokens sdk.Coins = sdk.Coins{sdk.NewInt64Coin(defaultLPSyntheticDenom, 10)} - defaultLiquidTokens sdk.Coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} - defaultLockDuration time.Duration = time.Second - oneLockupUser userLocks = userLocks{ + defaultLPDenom string = "lptoken" + defaultLPSyntheticDenom string = "lptoken/superbonding" + defaultLPTokens sdk.Coins = sdk.Coins{sdk.NewInt64Coin(defaultLPDenom, 10)} + defaultLPTokensDoubleAmt sdk.Coins = sdk.Coins{sdk.NewInt64Coin(defaultLPDenom, 20)} + defaultLPSyntheticTokens sdk.Coins = sdk.Coins{sdk.NewInt64Coin(defaultLPSyntheticDenom, 10)} + defaultLPSyntheticTokensDoubleAmt sdk.Coins = sdk.Coins{sdk.NewInt64Coin(defaultLPSyntheticDenom, 20)} + defaultLiquidTokens sdk.Coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} + defaultLockDuration time.Duration = time.Second + oneLockupUser userLocks = userLocks{ lockDurations: []time.Duration{time.Second}, lockAmounts: []sdk.Coins{defaultLPTokens}, } @@ -26,6 +28,10 @@ var ( lockDurations: []time.Duration{defaultLockDuration, 2 * defaultLockDuration}, lockAmounts: []sdk.Coins{defaultLPTokens, defaultLPTokens}, } + twoLockupUserDoubleAmt userLocks = userLocks{ + lockDurations: []time.Duration{defaultLockDuration, 2 * defaultLockDuration}, + lockAmounts: []sdk.Coins{defaultLPTokensDoubleAmt, defaultLPTokensDoubleAmt}, + } oneSyntheticLockupUser userLocks = userLocks{ lockDurations: []time.Duration{time.Second}, lockAmounts: []sdk.Coins{defaultLPSyntheticTokens}, @@ -34,6 +40,10 @@ var ( lockDurations: []time.Duration{defaultLockDuration, 2 * defaultLockDuration}, lockAmounts: []sdk.Coins{defaultLPSyntheticTokens, defaultLPSyntheticTokens}, } + twoSyntheticLockupUserDoubleAmt userLocks = userLocks{ + lockDurations: []time.Duration{defaultLockDuration, 2 * defaultLockDuration}, + lockAmounts: []sdk.Coins{defaultLPSyntheticTokensDoubleAmt, defaultLPSyntheticTokensDoubleAmt}, + } defaultRewardDenom string = "rewardDenom" otherDenom string = "someOtherDenom" ) @@ -102,7 +112,6 @@ func (s *KeeperTestSuite) SetupChangeRewardReceiver(changeRewardReceivers []chan // SetupUserSyntheticLocks takes an array of user locks and creates synthetic locks based on this array, then returns the respective account address byte array. func (s *KeeperTestSuite) SetupUserSyntheticLocks(users []userLocks) (accs []sdk.AccAddress) { accs = make([]sdk.AccAddress, len(users)) - coins := sdk.Coins{sdk.NewInt64Coin("lptoken", 10)} lockupID := uint64(1) for i, user := range users { s.Assert().Equal(len(user.lockDurations), len(user.lockAmounts)) @@ -112,6 +121,7 @@ func (s *KeeperTestSuite) SetupUserSyntheticLocks(users []userLocks) (accs []sdk } accs[i] = s.setupAddr(i, "", totalLockAmt) for j := 0; j < len(user.lockAmounts); j++ { + coins := sdk.Coins{sdk.NewInt64Coin("lptoken", user.lockAmounts[j][0].Amount.Int64())} s.LockTokens(accs[i], coins, user.lockDurations[j]) err := s.App.LockupKeeper.CreateSyntheticLockup(s.Ctx, lockupID, "lptoken/superbonding", user.lockDurations[j], false) lockupID++ From f32b21ea4fc233a15ce9a49a0ad05ff0e6bcf34e Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 26 Feb 2024 15:25:05 -0700 Subject: [PATCH 05/10] spelling --- x/incentives/keeper/distribute.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index 34f260463e4..0741ee2e03c 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -925,7 +925,7 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er // Instead of re-fetching the minimum value an underlying token must be to meet the minimum // requirement for distribution, we cache the values here. // While this isn't precise as it doesn't account for price impact, it is good enough for the sole - // purpose fo determining if we should distribute the token or not. + // purpose of determining if we should distribute the token or not. minDistrValueCache := &DistributionValueCache{ denomToMinValueMap: make(map[string]osmomath.Int), } From bc0bcf991810dff8c2b8b32860d991b5695fb46e Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 26 Feb 2024 16:15:27 -0700 Subject: [PATCH 06/10] change param to be Coin instead of int --- app/upgrades/v24/upgrades.go | 2 +- app/upgrades/v24/upgrades_test.go | 2 +- proto/osmosis/incentives/params.proto | 16 ++-- x/incentives/keeper/distribute.go | 25 +++--- x/incentives/keeper/distribute_test.go | 4 +- x/incentives/types/constants.go | 5 +- x/incentives/types/params.go | 17 ++-- x/incentives/types/params.pb.go | 114 +++++++++++++------------ 8 files changed, 91 insertions(+), 94 deletions(-) diff --git a/app/upgrades/v24/upgrades.go b/app/upgrades/v24/upgrades.go index c054cdb0fe8..b1e992a6574 100644 --- a/app/upgrades/v24/upgrades.go +++ b/app/upgrades/v24/upgrades.go @@ -43,7 +43,7 @@ func CreateUpgradeHandler( // Set the new min osmo value for distribution for the incentives module. // https://www.mintscan.io/osmosis/proposals/733 - keepers.IncentivesKeeper.SetParam(ctx, incentivestypes.KeyMinOsmoValueForDistr, incentivestypes.DefaultMinOsmoValueForDistr) + keepers.IncentivesKeeper.SetParam(ctx, incentivestypes.KeyMinValueForDistr, incentivestypes.DefaultMinValueForDistr) return migrations, nil } diff --git a/app/upgrades/v24/upgrades_test.go b/app/upgrades/v24/upgrades_test.go index 36c8980553e..7a58cc6de34 100644 --- a/app/upgrades/v24/upgrades_test.go +++ b/app/upgrades/v24/upgrades_test.go @@ -138,7 +138,7 @@ func (s *UpgradeTestSuite) TestUpgrade() { // Check that the new min osmo value for distribution has been set params := s.App.IncentivesKeeper.GetParams(s.Ctx) - s.Require().Equal(incentivestypes.DefaultMinOsmoValueForDistr, params.MinOsmoValueForDistribution) + s.Require().Equal(incentivestypes.DefaultMinValueForDistr, params.MinOsmoValueForDistribution) } func dummyUpgrade(s *UpgradeTestSuite) { diff --git a/proto/osmosis/incentives/params.proto b/proto/osmosis/incentives/params.proto index df90eec7f57..27f9113ded0 100644 --- a/proto/osmosis/incentives/params.proto +++ b/proto/osmosis/incentives/params.proto @@ -44,13 +44,11 @@ message Params { (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"internal_uptime\"" ]; - // min_osmo_value_for_distribution is the minimum amount a token must be worth - // in terms of OSMO to be eligible for distribution. If the token is worth - // less than this amount, it will not be distributed and is forfeited to the - // remaining distributees that are eligible. - string min_osmo_value_for_distribution = 5 [ - (gogoproto.customtype) = "cosmossdk.io/math.Int", - (gogoproto.moretags) = "yaml:\"min_osmo_value_for_distribution\"", - (gogoproto.nullable) = false - ]; + // min_value_for_distribution is the minimum amount a token must be worth + // in order to be eligible for distribution. If the token is worth + // less than this amount (or the route between the two denoms is not + // registered), it will not be distributed and is forfeited to the remaining + // distributees that are eligible. + cosmos.base.v1beta1.Coin min_value_for_distribution = 5 + [ (gogoproto.nullable) = false ]; } diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index 0741ee2e03c..6e2372f810c 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -622,13 +622,9 @@ func (k Keeper) distributeInternal( ) (sdk.Coins, error) { totalDistrCoins := sdk.NewCoins() - // Retrieve the min osmo value for distribution. + // Retrieve the min value for distribution. // If any distribution amount is valued less than what the param is set, it will be skipped. - minOsmoValueForDistr := k.GetParams(ctx).MinOsmoValueForDistribution - osmoDenom, err := k.tk.GetBaseDenom(ctx) - if err != nil { - return nil, err - } + minValueForDistr := k.GetParams(ctx).MinValueForDistribution remainCoins := gauge.Coins.Sub(gauge.DistributedCoins...) @@ -738,19 +734,19 @@ func (k Keeper) distributeInternal( amtIntBi.Quo(amtIntBi, lockSumTimesRemainingEpochsBi) - // Determine if the value to distribute is worth enough in OSMO to be distributed. - if coin.Denom == osmoDenom { - // If the denom is OSMO, no transformation is needed. - if amtInt.LT(minOsmoValueForDistr) { + // Determine if the value to distribute is worth enough in minValueForDistr denom to be distributed. + if coin.Denom == minValueForDistr.Denom { + // If the denom is the same as the minValueForDistr param, no transformation is needed. + if amtInt.LT(minValueForDistr.Amount) { continue } } else { - // If the denom is not OSMO, we need to transform the underlying to OSMO. + // If the denom is not the minValueForDistr denom, we need to transform the underlying to it. // Check if the denom exists in the cached values value, ok := minDistrValueCache.denomToMinValueMap[coin.Denom] if !ok { // Cache miss, figure out the value and add it to the cache - poolId, err := k.prk.GetPoolForDenomPairNoOrder(ctx, osmoDenom, coin.Denom) + poolId, err := k.prk.GetPoolForDenomPairNoOrder(ctx, minValueForDistr.Denom, coin.Denom) if err != nil { // If the pool denom pair pool route does not exist in protorev, we add a zero value to cache to avoid // querying the pool again. @@ -761,9 +757,8 @@ func (k Keeper) distributeInternal( if err != nil { return nil, err } - minOsmoCoin := sdk.Coin{Denom: osmoDenom, Amount: minOsmoValueForDistr} - minTokenRequiredForDistr, err := swapModule.CalcOutAmtGivenIn(ctx, pool, minOsmoCoin, coin.Denom, sdk.ZeroDec()) + minTokenRequiredForDistr, err := swapModule.CalcOutAmtGivenIn(ctx, pool, minValueForDistr, coin.Denom, sdk.ZeroDec()) if err != nil { return nil, err } @@ -814,7 +809,7 @@ func (k Keeper) distributeInternal( } } - err = k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins) + err := k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins) return totalDistrCoins, err } diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index ffca2d5f3eb..645042f2405 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -273,7 +273,7 @@ func (s *KeeperTestSuite) TestDistribute() { // set the base denom and min value for distribution err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, defaultRewardDenom) s.Require().NoError(err) - s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinOsmoValueForDistr, sdk.NewInt(1000)) + s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinValueForDistr, sdk.NewCoin(defaultRewardDenom, sdk.NewInt(1000))) baseDenom, err := s.App.TxFeesKeeper.GetBaseDenom(s.Ctx) s.Require().NoError(err) @@ -853,7 +853,7 @@ func (s *KeeperTestSuite) TestSyntheticDistribute() { // set the base denom and min value for distribution err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, defaultRewardDenom) s.Require().NoError(err) - s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinOsmoValueForDistr, sdk.NewInt(1000)) + s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyMinValueForDistr, sdk.NewCoin(defaultRewardDenom, sdk.NewInt(1000))) baseDenom, err := s.App.TxFeesKeeper.GetBaseDenom(s.Ctx) s.Require().NoError(err) diff --git a/x/incentives/types/constants.go b/x/incentives/types/constants.go index 974a4be0bb7..7881b258b0e 100644 --- a/x/incentives/types/constants.go +++ b/x/incentives/types/constants.go @@ -4,6 +4,7 @@ import ( time "time" sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" ) var ( @@ -16,6 +17,6 @@ var ( // PerpetualNumEpochsPaidOver is the number of epochs that must be given // for a gauge to be perpetual. For any other number of epochs // other than zero, the gauge is non-perpetual. Zero is invalid. - PerpetualNumEpochsPaidOver = uint64(0) - DefaultMinOsmoValueForDistr = sdkmath.NewInt(10000) // 0.01 + PerpetualNumEpochsPaidOver = uint64(0) + DefaultMinValueForDistr = sdk.NewCoin("uosmo", sdkmath.NewInt(10000)) // 0.01 OSMO ) diff --git a/x/incentives/types/params.go b/x/incentives/types/params.go index 3cc0f458cda..5e2cee8129f 100644 --- a/x/incentives/types/params.go +++ b/x/incentives/types/params.go @@ -10,7 +10,6 @@ import ( cltypes "github.com/osmosis-labs/osmosis/v23/x/concentrated-liquidity/types" epochtypes "github.com/osmosis-labs/osmosis/x/epochs/types" - sdkmath "cosmossdk.io/math" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) @@ -20,7 +19,7 @@ var ( KeyGroupCreationFee = []byte("GroupCreationFee") KeyCreatorWhitelist = []byte("CreatorWhitelist") KeyInternalUptime = []byte("InternalUptime") - KeyMinOsmoValueForDistr = []byte("MinOsmoValueForDistr") + KeyMinValueForDistr = []byte("MinValueForDistr") // 100 OSMO DefaultGroupCreationFee = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))) @@ -32,13 +31,13 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewParams takes an epoch distribution identifier and group creation fee, then returns an incentives Params struct. -func NewParams(distrEpochIdentifier string, groupCreationFee sdk.Coins, internalUptime time.Duration, minOsmoValueForDistr sdkmath.Int) Params { +func NewParams(distrEpochIdentifier string, groupCreationFee sdk.Coins, internalUptime time.Duration, minValueForDistr sdk.Coin) Params { return Params{ DistrEpochIdentifier: distrEpochIdentifier, GroupCreationFee: groupCreationFee, UnrestrictedCreatorWhitelist: []string{}, InternalUptime: internalUptime, - MinOsmoValueForDistribution: minOsmoValueForDistr, + MinValueForDistribution: minValueForDistr, } } @@ -49,7 +48,7 @@ func DefaultParams() Params { GroupCreationFee: DefaultGroupCreationFee, UnrestrictedCreatorWhitelist: []string{}, InternalUptime: DefaultConcentratedUptime, - MinOsmoValueForDistribution: DefaultMinOsmoValueForDistr, + MinValueForDistribution: DefaultMinValueForDistr, } } @@ -71,7 +70,7 @@ func (p Params) Validate() error { return err } - if err := ValidateMinOsmoValueForDistr(p.MinOsmoValueForDistribution); err != nil { + if err := ValidateMinValueForDistr(p.MinValueForDistribution); err != nil { return err } @@ -117,8 +116,8 @@ func ValidateInternalUptime(i interface{}) error { return nil } -func ValidateMinOsmoValueForDistr(i interface{}) error { - _, ok := i.(sdkmath.Int) +func ValidateMinValueForDistr(i interface{}) error { + _, ok := i.(sdk.Coin) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } @@ -132,6 +131,6 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyGroupCreationFee, &p.GroupCreationFee, ValidateGroupCreaionFee), paramtypes.NewParamSetPair(KeyCreatorWhitelist, &p.UnrestrictedCreatorWhitelist, osmoutils.ValidateAddressList), paramtypes.NewParamSetPair(KeyInternalUptime, &p.InternalUptime, ValidateInternalUptime), - paramtypes.NewParamSetPair(KeyMinOsmoValueForDistr, &p.MinOsmoValueForDistribution, ValidateMinOsmoValueForDistr), + paramtypes.NewParamSetPair(KeyMinValueForDistr, &p.MinValueForDistribution, ValidateMinValueForDistr), } } diff --git a/x/incentives/types/params.pb.go b/x/incentives/types/params.pb.go index 1427b26affb..c6b163b00de 100644 --- a/x/incentives/types/params.pb.go +++ b/x/incentives/types/params.pb.go @@ -4,7 +4,6 @@ package types import ( - cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" @@ -55,11 +54,12 @@ type Params struct { // the uptime of those incentives as well (i.e. distributions through volume // splitting incentives will use this uptime). InternalUptime time.Duration `protobuf:"bytes,4,opt,name=internal_uptime,json=internalUptime,proto3,stdduration" json:"internal_uptime" yaml:"internal_uptime"` - // min_osmo_value_for_distribution is the minimum amount a token must be worth - // in terms of OSMO to be eligible for distribution. If the token is worth - // less than this amount, it will not be distributed and is forfeited to the - // remaining distributees that are eligible. - MinOsmoValueForDistribution cosmossdk_io_math.Int `protobuf:"bytes,5,opt,name=min_osmo_value_for_distribution,json=minOsmoValueForDistribution,proto3,customtype=cosmossdk.io/math.Int" json:"min_osmo_value_for_distribution" yaml:"min_osmo_value_for_distribution"` + // min_value_for_distribution is the minimum amount a token must be worth + // in order to be eligible for distribution. If the token is worth + // less than this amount (or the route between the two denoms is not + // registered), it will not be distributed and is forfeited to the remaining + // distributees that are eligible. + MinValueForDistribution types.Coin `protobuf:"bytes,5,opt,name=min_value_for_distribution,json=minValueForDistribution,proto3" json:"min_value_for_distribution"` } func (m *Params) Reset() { *m = Params{} } @@ -123,6 +123,13 @@ func (m *Params) GetInternalUptime() time.Duration { return 0 } +func (m *Params) GetMinValueForDistribution() types.Coin { + if m != nil { + return m.MinValueForDistribution + } + return types.Coin{} +} + func init() { proto.RegisterType((*Params)(nil), "osmosis.incentives.Params") } @@ -130,39 +137,37 @@ func init() { func init() { proto.RegisterFile("osmosis/incentives/params.proto", fileDescriptor_1cc8b460d089f845) } var fileDescriptor_1cc8b460d089f845 = []byte{ - // 508 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0xc1, 0x6a, 0xd4, 0x40, - 0x18, 0xde, 0xb8, 0xb5, 0xd0, 0x08, 0x2a, 0xa1, 0x96, 0xb5, 0x6a, 0xb2, 0x06, 0x94, 0xf5, 0xd0, - 0x19, 0xdb, 0x82, 0x07, 0x8f, 0xbb, 0xb5, 0xd2, 0x93, 0x65, 0x41, 0x0b, 0x5e, 0x86, 0x49, 0x32, - 0x9b, 0x1d, 0x9a, 0xcc, 0x1f, 0x66, 0x26, 0xab, 0xfb, 0x10, 0x82, 0x47, 0x9f, 0xc1, 0xf7, 0x10, - 0x7a, 0xec, 0x51, 0x3c, 0xa4, 0xb2, 0xfb, 0x06, 0xfb, 0x04, 0x92, 0x99, 0x44, 0x17, 0x11, 0x7b, - 0x4a, 0xe6, 0xff, 0xbe, 0xf9, 0xbf, 0xff, 0xfb, 0xbf, 0xc4, 0x0d, 0x40, 0xe5, 0xa0, 0xb8, 0xc2, - 0x5c, 0xc4, 0x4c, 0x68, 0x3e, 0x63, 0x0a, 0x17, 0x54, 0xd2, 0x5c, 0xa1, 0x42, 0x82, 0x06, 0xcf, - 0x6b, 0x08, 0xe8, 0x0f, 0x61, 0x77, 0x3b, 0x85, 0x14, 0x0c, 0x8c, 0xeb, 0x37, 0xcb, 0xdc, 0xf5, - 0x63, 0x43, 0xc5, 0x11, 0x55, 0x0c, 0xcf, 0xf6, 0x23, 0xa6, 0xe9, 0x3e, 0x8e, 0x81, 0x8b, 0x16, - 0x4f, 0x01, 0xd2, 0x8c, 0x61, 0x73, 0x8a, 0xca, 0x09, 0x4e, 0x4a, 0x49, 0x35, 0x87, 0x06, 0x0f, - 0xbf, 0x6d, 0xb8, 0x9b, 0xa7, 0x46, 0xda, 0x3b, 0x73, 0x77, 0x12, 0xae, 0xb4, 0x24, 0xac, 0x80, - 0x78, 0x4a, 0x78, 0x52, 0x2b, 0x4f, 0x38, 0x93, 0x3d, 0xa7, 0xef, 0x0c, 0xb6, 0x86, 0x8f, 0x57, - 0x55, 0xf0, 0x68, 0x4e, 0xf3, 0xec, 0x65, 0xf8, 0x6f, 0x5e, 0x38, 0xde, 0x36, 0xc0, 0xab, 0xba, - 0x7e, 0xf2, 0xbb, 0xec, 0xcd, 0x5d, 0x2f, 0x95, 0x50, 0x16, 0x24, 0x96, 0xcc, 0x68, 0x93, 0x09, - 0x63, 0xbd, 0x1b, 0xfd, 0xee, 0xe0, 0xd6, 0xc1, 0x7d, 0x64, 0x0d, 0xa0, 0xda, 0x00, 0x6a, 0x0c, - 0xa0, 0x11, 0x70, 0x31, 0x7c, 0x7e, 0x51, 0x05, 0x9d, 0xaf, 0x57, 0xc1, 0x20, 0xe5, 0x7a, 0x5a, - 0x46, 0x28, 0x86, 0x1c, 0x37, 0x6e, 0xed, 0x63, 0x4f, 0x25, 0xe7, 0x58, 0xcf, 0x0b, 0xa6, 0xcc, - 0x05, 0x35, 0xbe, 0x6b, 0x64, 0x46, 0x8d, 0xca, 0x31, 0x63, 0x1e, 0xb8, 0x7e, 0x29, 0x24, 0x53, - 0x5a, 0xf2, 0x58, 0xb3, 0xc4, 0x4e, 0x00, 0x92, 0x7c, 0x98, 0x72, 0xcd, 0x32, 0xae, 0x74, 0xaf, - 0xdb, 0xef, 0x0e, 0xb6, 0x86, 0xcf, 0x56, 0x55, 0xf0, 0xc4, 0x7a, 0xfb, 0x3f, 0x3f, 0x1c, 0x3f, - 0x5c, 0x27, 0x8c, 0x2c, 0x7e, 0xd6, 0xc2, 0xde, 0xc4, 0xbd, 0xc3, 0x85, 0x66, 0x52, 0xd0, 0x8c, - 0x94, 0x85, 0xe6, 0x39, 0xeb, 0x6d, 0xf4, 0x1d, 0x63, 0xd4, 0x26, 0x81, 0xda, 0x24, 0xd0, 0x51, - 0x93, 0xc4, 0x30, 0xac, 0x8d, 0xae, 0xaa, 0x60, 0xc7, 0x0e, 0xf0, 0xd7, 0xfd, 0xf0, 0xcb, 0x55, - 0xe0, 0x8c, 0x6f, 0xb7, 0xd5, 0xb7, 0xa6, 0xe8, 0x7d, 0x72, 0xdc, 0x20, 0xe7, 0x82, 0xd4, 0x8b, - 0x20, 0x33, 0x9a, 0x95, 0x8c, 0x4c, 0x40, 0x12, 0xb3, 0x7f, 0x1e, 0x95, 0x75, 0xdf, 0xde, 0x4d, - 0x13, 0xdb, 0xeb, 0xba, 0xfb, 0x8f, 0x2a, 0xb8, 0x67, 0x97, 0xa6, 0x92, 0x73, 0xc4, 0x01, 0xe7, - 0x54, 0x4f, 0xd1, 0x89, 0xd0, 0xab, 0x2a, 0x78, 0x6a, 0x65, 0xaf, 0xe9, 0x16, 0x8e, 0x1f, 0xe4, - 0x5c, 0xbc, 0x51, 0x39, 0xbc, 0xab, 0xf1, 0x63, 0x90, 0x47, 0x6b, 0xe8, 0xf0, 0xf4, 0x62, 0xe1, - 0x3b, 0x97, 0x0b, 0xdf, 0xf9, 0xb9, 0xf0, 0x9d, 0xcf, 0x4b, 0xbf, 0x73, 0xb9, 0xf4, 0x3b, 0xdf, - 0x97, 0x7e, 0xe7, 0xfd, 0x8b, 0xb5, 0xf8, 0x9a, 0xcf, 0x7a, 0x2f, 0xa3, 0x91, 0x6a, 0x0f, 0x78, - 0x76, 0x70, 0x88, 0x3f, 0xae, 0xff, 0x0a, 0x26, 0xd2, 0x68, 0xd3, 0x2c, 0xea, 0xf0, 0x57, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x2f, 0x33, 0x33, 0xc6, 0x2d, 0x03, 0x00, 0x00, + // 475 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0xdd, 0x6a, 0xd4, 0x40, + 0x18, 0xdd, 0xb8, 0x6b, 0xa1, 0x11, 0x54, 0x42, 0xa9, 0x71, 0xd1, 0x64, 0x0d, 0x08, 0xeb, 0x45, + 0x33, 0xb6, 0x05, 0x2f, 0xbc, 0xcc, 0xd6, 0x82, 0x77, 0x25, 0xa0, 0x05, 0x11, 0x42, 0x7e, 0xbe, + 0x64, 0x3f, 0x4c, 0xf2, 0x85, 0x99, 0xc9, 0xea, 0xbe, 0x85, 0xe0, 0x8d, 0xcf, 0xe0, 0x93, 0xf4, + 0xb2, 0x97, 0x5e, 0x6d, 0x65, 0xf7, 0x0d, 0xf6, 0x09, 0x24, 0x93, 0x44, 0x17, 0x51, 0xaf, 0x92, + 0x39, 0xe7, 0x7c, 0x73, 0xe6, 0xcc, 0x19, 0xdd, 0x26, 0x51, 0x90, 0x40, 0xc1, 0xb0, 0x8c, 0xa1, + 0x94, 0xb8, 0x00, 0xc1, 0xaa, 0x90, 0x87, 0x85, 0x70, 0x2b, 0x4e, 0x92, 0x0c, 0xa3, 0x13, 0xb8, + 0xbf, 0x05, 0xe3, 0x83, 0x8c, 0x32, 0x52, 0x34, 0x6b, 0xfe, 0x5a, 0xe5, 0xd8, 0x8a, 0x95, 0x94, + 0x45, 0xa1, 0x00, 0xb6, 0x38, 0x8e, 0x40, 0x86, 0xc7, 0x2c, 0x26, 0x2c, 0x7b, 0x3e, 0x23, 0xca, + 0x72, 0x60, 0x6a, 0x15, 0xd5, 0x29, 0x4b, 0x6a, 0x1e, 0x4a, 0xa4, 0x8e, 0x77, 0xbe, 0x8c, 0xf4, + 0xbd, 0x0b, 0x65, 0x6d, 0x5c, 0xea, 0x87, 0x09, 0x0a, 0xc9, 0x03, 0xa8, 0x28, 0x9e, 0x07, 0x98, + 0x34, 0xce, 0x29, 0x02, 0x37, 0xb5, 0x89, 0x36, 0xdd, 0xf7, 0x9e, 0x6c, 0x57, 0xf6, 0xe3, 0x65, + 0x58, 0xe4, 0x2f, 0x9d, 0xbf, 0xeb, 0x1c, 0xff, 0x40, 0x11, 0xaf, 0x1a, 0xfc, 0xf5, 0x2f, 0xd8, + 0x58, 0xea, 0x46, 0xc6, 0xa9, 0xae, 0x82, 0x98, 0x83, 0xf2, 0x0e, 0x52, 0x00, 0xf3, 0xd6, 0x64, + 0x38, 0xbd, 0x73, 0xf2, 0xd0, 0x6d, 0x03, 0xb8, 0x4d, 0x00, 0xb7, 0x0b, 0xe0, 0xce, 0x08, 0x4b, + 0xef, 0xf9, 0xd5, 0xca, 0x1e, 0x7c, 0xbb, 0xb1, 0xa7, 0x19, 0xca, 0x79, 0x1d, 0xb9, 0x31, 0x15, + 0xac, 0x4b, 0xdb, 0x7e, 0x8e, 0x44, 0xf2, 0x81, 0xc9, 0x65, 0x05, 0x42, 0x0d, 0x08, 0xff, 0xbe, + 0xb2, 0x99, 0x75, 0x2e, 0xe7, 0x00, 0x06, 0xe9, 0x56, 0x5d, 0x72, 0x10, 0x92, 0x63, 0x2c, 0x21, + 0x69, 0x4f, 0x40, 0x3c, 0xf8, 0x38, 0x47, 0x09, 0x39, 0x0a, 0x69, 0x0e, 0x27, 0xc3, 0xe9, 0xbe, + 0xf7, 0x6c, 0xbb, 0xb2, 0x9f, 0xb6, 0xd9, 0xfe, 0xaf, 0x77, 0xfc, 0x47, 0xbb, 0x82, 0x59, 0xcb, + 0x5f, 0xf6, 0xb4, 0x91, 0xea, 0xf7, 0xb0, 0x94, 0xc0, 0xcb, 0x30, 0x0f, 0xea, 0x4a, 0x62, 0x01, + 0xe6, 0x68, 0xa2, 0xa9, 0xa0, 0x6d, 0x13, 0x6e, 0xdf, 0x84, 0x7b, 0xd6, 0x35, 0xe1, 0x39, 0x4d, + 0xd0, 0xed, 0xca, 0x3e, 0x6c, 0x0f, 0xf0, 0xc7, 0xbc, 0xf3, 0xf5, 0xc6, 0xd6, 0xfc, 0xbb, 0x3d, + 0xfa, 0x46, 0x81, 0xc6, 0x7b, 0x7d, 0x5c, 0x60, 0x19, 0x2c, 0xc2, 0xbc, 0x86, 0x20, 0x25, 0x1e, + 0xa8, 0x9b, 0xc7, 0xa8, 0x6e, 0x76, 0x34, 0x6f, 0x77, 0x96, 0xff, 0xbc, 0xdb, 0x51, 0x63, 0xe9, + 0x3f, 0x28, 0xb0, 0x7c, 0xdb, 0xec, 0x70, 0x4e, 0xfc, 0x6c, 0x67, 0xde, 0xbb, 0xb8, 0x5a, 0x5b, + 0xda, 0xf5, 0xda, 0xd2, 0x7e, 0xac, 0x2d, 0xed, 0xf3, 0xc6, 0x1a, 0x5c, 0x6f, 0xac, 0xc1, 0xf7, + 0x8d, 0x35, 0x78, 0xf7, 0x62, 0xa7, 0x8c, 0xee, 0x91, 0x1e, 0xe5, 0x61, 0x24, 0xfa, 0x05, 0x5b, + 0x9c, 0x9c, 0xb2, 0x4f, 0xbb, 0x0f, 0x5b, 0x15, 0x14, 0xed, 0xa9, 0xd8, 0xa7, 0x3f, 0x03, 0x00, + 0x00, 0xff, 0xff, 0x0a, 0x2b, 0xf1, 0x4a, 0xfb, 0x02, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -186,21 +191,21 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size := m.MinOsmoValueForDistribution.Size() - i -= size - if _, err := m.MinOsmoValueForDistribution.MarshalTo(dAtA[i:]); err != nil { + size, err := m.MinValueForDistribution.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { return 0, err } + i -= size i = encodeVarintParams(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x2a - n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.InternalUptime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InternalUptime):]) - if err1 != nil { - return 0, err1 + n2, err2 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.InternalUptime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InternalUptime):]) + if err2 != nil { + return 0, err2 } - i -= n1 - i = encodeVarintParams(dAtA, i, uint64(n1)) + i -= n2 + i = encodeVarintParams(dAtA, i, uint64(n2)) i-- dAtA[i] = 0x22 if len(m.UnrestrictedCreatorWhitelist) > 0 { @@ -271,7 +276,7 @@ func (m *Params) Size() (n int) { } l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.InternalUptime) n += 1 + l + sovParams(uint64(l)) - l = m.MinOsmoValueForDistribution.Size() + l = m.MinValueForDistribution.Size() n += 1 + l + sovParams(uint64(l)) return n } @@ -444,9 +449,9 @@ func (m *Params) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MinOsmoValueForDistribution", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MinValueForDistribution", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowParams @@ -456,23 +461,22 @@ func (m *Params) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthParams } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthParams } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MinOsmoValueForDistribution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MinValueForDistribution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex From 146c6d9283bba6685588079dd5bdbba072f4472f Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 26 Feb 2024 16:19:54 -0700 Subject: [PATCH 07/10] lints --- CHANGELOG.md | 2 +- app/upgrades/v24/upgrades.go | 2 +- app/upgrades/v24/upgrades_test.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce7941fcf67..16c74426f21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#7555](https://github.com/osmosis-labs/osmosis/pull/7555) Refactor taker fees, distribute via a single module account, track once at epoch * [#7562](https://github.com/osmosis-labs/osmosis/pull/7562) Speedup Protorev estimation logic by removing unnecessary taker fee simulations. * [#7595](https://github.com/osmosis-labs/osmosis/pull/7595) Fix cosmwasm pool model code ID migration. -* [#7615](https://github.com/osmosis-labs/osmosis/pull/7615) Min OSMO value of underlying for epoch distribution. +* [#7615](https://github.com/osmosis-labs/osmosis/pull/7615) Min value param for epoch distribution. ### State Compatible diff --git a/app/upgrades/v24/upgrades.go b/app/upgrades/v24/upgrades.go index b1e992a6574..560e30cb040 100644 --- a/app/upgrades/v24/upgrades.go +++ b/app/upgrades/v24/upgrades.go @@ -41,7 +41,7 @@ func CreateUpgradeHandler( // since we only need the pool indexed TWAPs. keepers.TwapKeeper.DeleteAllHistoricalTimeIndexedTWAPs(ctx) - // Set the new min osmo value for distribution for the incentives module. + // Set the new min value for distribution for the incentives module. // https://www.mintscan.io/osmosis/proposals/733 keepers.IncentivesKeeper.SetParam(ctx, incentivestypes.KeyMinValueForDistr, incentivestypes.DefaultMinValueForDistr) diff --git a/app/upgrades/v24/upgrades_test.go b/app/upgrades/v24/upgrades_test.go index 7a58cc6de34..eae183d4a72 100644 --- a/app/upgrades/v24/upgrades_test.go +++ b/app/upgrades/v24/upgrades_test.go @@ -136,9 +136,9 @@ func (s *UpgradeTestSuite) TestUpgrade() { // INCENTIVES Tests // - // Check that the new min osmo value for distribution has been set + // Check that the new min value for distribution has been set params := s.App.IncentivesKeeper.GetParams(s.Ctx) - s.Require().Equal(incentivestypes.DefaultMinValueForDistr, params.MinOsmoValueForDistribution) + s.Require().Equal(incentivestypes.DefaultMinValueForDistr, params.MinValueForDistribution) } func dummyUpgrade(s *UpgradeTestSuite) { From 0e5aea43f97e95e7ddd45b1f20ffccc4fb41c216 Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Mon, 26 Feb 2024 16:48:08 -0700 Subject: [PATCH 08/10] address tests --- x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go | 4 ++-- x/incentives/keeper/keeper_test.go | 2 ++ x/superfluid/keeper/keeper_test.go | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go b/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go index 6772b2c7144..f52d466ef13 100644 --- a/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go +++ b/x/cosmwasmpool/cosmwasm/msg/transmuter/transmuter_test.go @@ -51,7 +51,7 @@ func (s *TransmuterSuite) TestFunctionalTransmuter() { ) // Set base denom - err := s.App.TxFeesKeeper.SetBaseDenom(s.Ctx, uosmo) + s.App.IncentivesKeeper.SetParam(s.Ctx, incentivetypes.KeyMinValueForDistr, sdk.NewCoin("uosmo", osmomath.NewInt(10000))) // Create Transmuter pool transmuter := s.PrepareCosmWasmPool() @@ -80,7 +80,7 @@ func (s *TransmuterSuite) TestFunctionalTransmuter() { // Lock shares shareCoins := sdk.NewCoins(shareCoin) lockDuration := time.Hour - _, err = s.App.LockupKeeper.CreateLock(s.Ctx, s.TestAccs[0], shareCoins, lockDuration) + _, err := s.App.LockupKeeper.CreateLock(s.Ctx, s.TestAccs[0], shareCoins, lockDuration) s.Require().NoError(err) // Create gauge diff --git a/x/incentives/keeper/keeper_test.go b/x/incentives/keeper/keeper_test.go index af623a2d2db..9d91987c85c 100644 --- a/x/incentives/keeper/keeper_test.go +++ b/x/incentives/keeper/keeper_test.go @@ -12,6 +12,7 @@ import ( cltypes "github.com/osmosis-labs/osmosis/v23/x/concentrated-liquidity/types" "github.com/osmosis-labs/osmosis/v23/x/incentives/keeper" "github.com/osmosis-labs/osmosis/v23/x/incentives/types" + incentivetypes "github.com/osmosis-labs/osmosis/v23/x/incentives/types" ) type KeeperTestSuite struct { @@ -27,6 +28,7 @@ func (s *KeeperTestSuite) SetupTest() { lockableDurations := s.App.IncentivesKeeper.GetLockableDurations(s.Ctx) lockableDurations = append(lockableDurations, 2*time.Second) s.App.IncentivesKeeper.SetLockableDurations(s.Ctx, lockableDurations) + s.App.IncentivesKeeper.SetParam(s.Ctx, incentivetypes.KeyMinValueForDistr, sdk.NewCoin("stake", osmomath.NewInt(1))) } func TestKeeperTestSuite(t *testing.T) { diff --git a/x/superfluid/keeper/keeper_test.go b/x/superfluid/keeper/keeper_test.go index 6bb7ecc8f07..8749acd8dfe 100644 --- a/x/superfluid/keeper/keeper_test.go +++ b/x/superfluid/keeper/keeper_test.go @@ -14,6 +14,7 @@ import ( "github.com/osmosis-labs/osmosis/v23/app/apptesting" "github.com/osmosis-labs/osmosis/v23/x/gamm/pool-models/balancer" gammtypes "github.com/osmosis-labs/osmosis/v23/x/gamm/types" + incentivetypes "github.com/osmosis-labs/osmosis/v23/x/incentives/types" lockuptypes "github.com/osmosis-labs/osmosis/v23/x/lockup/types" minttypes "github.com/osmosis-labs/osmosis/v23/x/mint/types" "github.com/osmosis-labs/osmosis/v23/x/superfluid/keeper" @@ -78,6 +79,7 @@ func (s *KeeperTestSuite) SetupTest() { distributionParams.BonusProposerReward = osmomath.ZeroDec() distributionParams.CommunityTax = osmomath.ZeroDec() s.App.DistrKeeper.SetParams(s.Ctx, distributionParams) + s.App.IncentivesKeeper.SetParam(s.Ctx, incentivetypes.KeyMinValueForDistr, sdk.NewCoin("stake", osmomath.NewInt(1))) } func (s *KeeperTestSuite) SetupDefaultPool() { From b9d5d1a1bed6644286be0914c43860fec9350ea3 Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Tue, 12 Mar 2024 11:01:14 -0500 Subject: [PATCH 09/10] Update x/incentives/keeper/distribute.go Co-authored-by: Nicolas Lara --- x/incentives/keeper/distribute.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index 6e2372f810c..0797696755d 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -774,8 +774,12 @@ func (k Keeper) distributeInternal( } else { // Cache hit, use the value + // This route does not exist in protorev so a zero value has been added when a cache miss occurred + if value.IsZero() { + continue + } // Check if the underlying is worth enough in the token to be distributed. - if amtInt.LT(value) || value.IsZero() { + if amtInt.LT(value) { continue } } From d2ce9d288576f79a3713c69d5ceb4e39ad3a48bb Mon Sep 17 00:00:00 2001 From: Adam Tucker Date: Tue, 12 Mar 2024 11:47:18 -0600 Subject: [PATCH 10/10] fmt --- x/incentives/keeper/distribute.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index 0797696755d..dc40c65d99c 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -774,7 +774,7 @@ func (k Keeper) distributeInternal( } else { // Cache hit, use the value - // This route does not exist in protorev so a zero value has been added when a cache miss occurred + // This route does not exist in protorev so a zero value has been added when a cache miss occurred if value.IsZero() { continue }