Skip to content

Commit

Permalink
deleted gas charges
Browse files Browse the repository at this point in the history
  • Loading branch information
keruch committed Sep 12, 2024
1 parent 9c43bec commit 380559f
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 521 deletions.
7 changes: 3 additions & 4 deletions app/upgrades/v4/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,9 @@ func migrateStreamer(ctx sdk.Context, sk streamerkeeper.Keeper, ek *epochskeeper
func migrateIncentivesParams(ctx sdk.Context, ik *incentiveskeeper.Keeper) {
params := ik.GetParams(ctx)
defaultParams := incentivestypes.DefaultParams()
params.CreateGaugeFee = defaultParams.CreateGaugeFee
params.AddToGaugeFee = defaultParams.AddToGaugeFee
params.BaseGasFeeForCreateGauge = defaultParams.BaseGasFeeForCreateGauge
params.BaseGasFeeForAddRewardToGauge = defaultParams.BaseGasFeeForAddRewardToGauge
params.CreateGaugeBaseFee = defaultParams.CreateGaugeBaseFee
params.AddToGaugeBaseFee = defaultParams.AddToGaugeBaseFee
params.AddDenomFee = defaultParams.AddDenomFee
ik.SetParams(ctx, params)
}

Expand Down
24 changes: 13 additions & 11 deletions proto/dymensionxyz/dymension/incentives/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,23 @@ message Params {
// (day, week, etc.)
string distr_epoch_identifier = 1
[ (gogoproto.moretags) = "yaml:\"distr_epoch_identifier\"" ];
// CreateGaugeFee is the fee required to create a new gauge.
string create_gauge_fee = 2 [
// CreateGaugeBaseFee is a base fee required to create a new gauge. The final
// fee is calculated as
// Fee = CreateGaugeBaseFee + AddDenomFee * (len(Denoms) + len(GaugeDenoms)).
string create_gauge_base_fee = 2 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"
];
// AddToGaugeFee is the fee required to add to gauge.
string add_to_gauge_fee = 3 [
// AddToGaugeBaseFee is a base fee required to add to gauge. The final
// fee is calculated as
// Fee = AddToGaugeBaseFee + AddDenomFee * len(Denoms).
string add_to_gauge_base_fee = 3 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"
];
// AddDenomFee is a fee charged for adding every new denom to the gauge.
string add_denom_fee = 4 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"
];
// BaseGasFeeForCreateGauge is the gas fee for creating a gauge.
// This gas is charged for each denom while creating a gauge.
uint64 base_gas_fee_for_create_gauge = 4;
// BaseGasFeeForAddRewardToGauge is the gas fee for adding reward to gauges.
// This gas is charged for each denom while adding to a gauge plus for
// each denom the gauge already holds.
uint64 base_gas_fee_for_add_reward_to_gauge = 5;
}
28 changes: 16 additions & 12 deletions x/incentives/keeper/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ func (k Keeper) CreateGauge(ctx sdk.Context, isPerpetual bool, owner sdk.AccAddr
return 0, fmt.Errorf("denom does not exist: %s", distrTo.Denom)
}

// Charge fess based on the number of coins to add
// Fee = CreateGaugeBaseFee + AddDenomFee * NumDenoms
params := k.GetParams(ctx)
fee := params.CreateGaugeBaseFee.Add(params.AddDenomFee.MulRaw(int64(len(coins))))
if err := k.chargeFeeIfSufficientFeeDenomBalance(ctx, owner, fee, coins); err != nil {
return 0, err
}

gauge := types.Gauge{
Id: k.GetLastGaugeID(ctx) + 1,
IsPerpetual: isPerpetual,
Expand All @@ -119,12 +127,6 @@ func (k Keeper) CreateGauge(ctx sdk.Context, isPerpetual bool, owner sdk.AccAddr
NumEpochsPaidOver: numEpochsPaidOver,
}

// Fixed gas consumption create gauge based on the number of coins to add
baseGasFee := k.GetParams(ctx).BaseGasFeeForCreateGauge
denoms := uint64(len(gauge.Coins))
// Both baseGasFee and denoms are relatively small, so their multiplication shouldn't lead to overflow in practice
ctx.GasMeter().ConsumeGas(baseGasFee*denoms, "scaling gas cost for creating gauge rewards")

if err := k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, gauge.Coins); err != nil {
return 0, err
}
Expand Down Expand Up @@ -156,13 +158,15 @@ func (k Keeper) AddToGaugeRewards(ctx sdk.Context, owner sdk.AccAddress, coins s
return types.UnexpectedFinishedGaugeError{GaugeId: gaugeID}
}

// Fixed gas consumption adding reward to gauges based on the number of coins to add
baseGasFee := k.GetParams(ctx).BaseGasFeeForAddRewardToGauge
denoms := uint64(len(coins) + len(gauge.Coins))
// Both baseGasFee and denoms are relatively small, so their multiplication shouldn't lead to overflow in practice
ctx.GasMeter().ConsumeGas(baseGasFee*denoms, "scaling gas cost for adding to gauge rewards")
// Charge fess based on the number of coins to add
// Fee = AddToGaugeBaseFee + AddDenomFee * (NumAddedDenoms + NumGaugeDenoms)
params := k.GetParams(ctx)
fee := params.AddToGaugeBaseFee.Add(params.AddDenomFee.MulRaw(int64(len(coins) + len(gauge.Coins))))
if err = k.chargeFeeIfSufficientFeeDenomBalance(ctx, owner, fee, coins); err != nil {
return err
}

if err := k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, coins); err != nil {
if err = k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, coins); err != nil {
return err
}

Expand Down
200 changes: 4 additions & 196 deletions x/incentives/keeper/gauge_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package keeper_test

import (
"fmt"
"time"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
"pgregory.net/rapid"

"github.com/dymensionxyz/dymension/v3/app/apptesting"
"github.com/dymensionxyz/dymension/v3/x/incentives/types"
Expand All @@ -26,6 +23,8 @@ func (suite *KeeperTestSuite) TestInvalidDurationGaugeCreationValidation() {
Denom: defaultLPDenom,
Duration: defaultLockDuration / 2, // 0.5 second, invalid duration
}
// add tokens for fees
suite.FundAcc(addrs[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, types.DefaultCreateGaugeFee.MulRaw(2))))
_, err := suite.App.IncentivesKeeper.CreateGauge(suite.Ctx, false, addrs[0], defaultLiquidTokens, distrTo, time.Time{}, 1)
suite.Require().Error(err)

Expand All @@ -45,6 +44,8 @@ func (suite *KeeperTestSuite) TestNonExistentDenomGaugeCreation() {
Denom: defaultLPDenom,
Duration: defaultLockDuration,
}
// add tokens for fees
suite.FundAcc(addrs[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, types.DefaultCreateGaugeFee.MulRaw(2))))
_, err := suite.App.IncentivesKeeper.CreateGauge(suite.Ctx, false, addrNoSupply, defaultLiquidTokens, distrTo, time.Time{}, 1)
suite.Require().Error(err)

Expand Down Expand Up @@ -324,196 +325,3 @@ func (suite *KeeperTestSuite) TestChargeFeeIfSufficientFeeDenomBalance() {
})
}
}

func (suite *KeeperTestSuite) TestAddToGaugeRewards() {
params := suite.App.IncentivesKeeper.GetParams(suite.Ctx)
addr := apptesting.CreateRandomAccounts(1)[0]

testCases := []struct {
name string
owner sdk.AccAddress
coinsToAdd sdk.Coins
gaugeCoins sdk.Coins
gaugeId uint64
minimumGasConsumed uint64

expectErr bool
}{
{
name: "valid case: valid gauge",
owner: addr,
coinsToAdd: sdk.NewCoins(
sdk.NewCoin("uosmo", sdk.NewInt(100000)),
sdk.NewCoin("atom", sdk.NewInt(99999)),
),
gaugeCoins: sdk.Coins{
sdk.NewInt64Coin("stake1", 12),
},
gaugeId: 1,
minimumGasConsumed: 3 * params.BaseGasFeeForAddRewardToGauge,
expectErr: false,
},
{
name: "valid case: valid gauge with >4 denoms to add",
owner: addr,
coinsToAdd: sdk.NewCoins(
sdk.NewCoin("uosmo", sdk.NewInt(100000)),
sdk.NewCoin("atom", sdk.NewInt(99999)),
sdk.NewCoin("mars", sdk.NewInt(88888)),
sdk.NewCoin("akash", sdk.NewInt(77777)),
sdk.NewCoin("eth", sdk.NewInt(6666)),
sdk.NewCoin("usdc", sdk.NewInt(555)),
sdk.NewCoin("dai", sdk.NewInt(4444)),
sdk.NewCoin("ust", sdk.NewInt(3333)),
),
gaugeCoins: sdk.Coins{
sdk.NewInt64Coin("stake1", 12),
},
gaugeId: 1,
minimumGasConsumed: 9 * params.BaseGasFeeForAddRewardToGauge,
expectErr: false,
},
{
name: "valid case: valid gauge with >4 initial denoms",
owner: addr,
coinsToAdd: sdk.NewCoins(
sdk.NewCoin("uosmo", sdk.NewInt(100000)),
sdk.NewCoin("atom", sdk.NewInt(99999)),
sdk.NewCoin("mars", sdk.NewInt(88888)),
sdk.NewCoin("akash", sdk.NewInt(77777)),
sdk.NewCoin("eth", sdk.NewInt(6666)),
sdk.NewCoin("usdc", sdk.NewInt(555)),
sdk.NewCoin("dai", sdk.NewInt(4444)),
sdk.NewCoin("ust", sdk.NewInt(3333)),
),
gaugeCoins: sdk.Coins{
sdk.NewCoin("uosmo", sdk.NewInt(100000)),
sdk.NewCoin("atom", sdk.NewInt(99999)),
sdk.NewCoin("mars", sdk.NewInt(88888)),
sdk.NewCoin("akash", sdk.NewInt(77777)),
sdk.NewCoin("eth", sdk.NewInt(6666)),
sdk.NewCoin("usdc", sdk.NewInt(555)),
sdk.NewCoin("dai", sdk.NewInt(4444)),
sdk.NewCoin("ust", sdk.NewInt(3333)),
},
gaugeId: 1,
minimumGasConsumed: 16 * params.BaseGasFeeForAddRewardToGauge,
expectErr: false,
},
{
name: "invalid case: gauge Id is not valid",
owner: addr,
coinsToAdd: sdk.NewCoins(
sdk.NewCoin("uosmo", sdk.NewInt(100000)),
sdk.NewCoin("atom", sdk.NewInt(99999)),
),
gaugeCoins: sdk.Coins{
sdk.NewInt64Coin("stake1", 12),
sdk.NewInt64Coin("stake2", 12),
sdk.NewInt64Coin("stake3", 12),
},
gaugeId: 0,
minimumGasConsumed: uint64(0),
expectErr: true,
},
}

for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest()
_, _, existingGaugeCoins, _ := suite.SetupNewGauge(true, sdk.NewCoins(tc.gaugeCoins...))

suite.FundAcc(tc.owner, tc.coinsToAdd)

existingGasConsumed := suite.Ctx.GasMeter().GasConsumed()

err := suite.App.IncentivesKeeper.AddToGaugeRewards(suite.Ctx, tc.owner, tc.coinsToAdd, tc.gaugeId)
if tc.expectErr {
suite.Require().Error(err)

// balance shouldn't change in the module
balance := suite.App.BankKeeper.GetAllBalances(suite.Ctx, suite.App.AccountKeeper.GetModuleAddress(types.ModuleName))
suite.Require().Equal(existingGaugeCoins, balance)

} else {
suite.Require().NoError(err)

// Ensure that at least the minimum amount of gas was charged (based on number of additional gauge coins)
gasConsumed := suite.Ctx.GasMeter().GasConsumed() - existingGasConsumed
fmt.Println(gasConsumed, tc.minimumGasConsumed)
suite.Require().True(gasConsumed >= tc.minimumGasConsumed)

// existing coins gets added to the module when we create gauge and add to gauge
expectedCoins := existingGaugeCoins.Add(tc.coinsToAdd...)

// check module account balance, should go up
balance := suite.App.BankKeeper.GetAllBalances(suite.Ctx, suite.App.AccountKeeper.GetModuleAddress(types.ModuleName))
suite.Require().Equal(expectedCoins, balance)

// check gauge coins should go up
gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, tc.gaugeId)
suite.Require().NoError(err)

suite.Require().Equal(expectedCoins, gauge.Coins)
}
})
}
}

func (s *KeeperTestSuite) TestRapidTestAddToGaugeRewards() {
rapid.Check(s.T(), func(t *rapid.T) {
// Generate random data
existingDenoms := make(map[string]struct{})
gcGen := rapid.Custom[sdk.Coin](func(t *rapid.T) sdk.Coin {
return sdk.Coin{
Denom: rapid.StringOfN(rapid.RuneFrom([]rune{'a', 'b', 'c'}), 5, 100, -1).
Filter(func(s string) bool {
_, ok := existingDenoms[s]
existingDenoms[s] = struct{}{}
return !ok
}).
Draw(t, "denom"),
Amount: math.NewInt(rapid.Int64Range(1, 100_000).Draw(t, "coins")),
}
})
gaugeCoins := sdk.NewCoins(rapid.SliceOfN[sdk.Coin](gcGen, 1, 100_000).Draw(t, "gaugeCoins")...)
coinsToAdd := sdk.NewCoins(rapid.SliceOfN[sdk.Coin](gcGen, 1, 100_000).Draw(t, "coinsToAdd")...)

s.SetupTest()

// Create a new gauge
_, _, existingGaugeCoins, _ := s.SetupNewGauge(true, gaugeCoins)
owner := apptesting.CreateRandomAccounts(1)[0]
// Fund the owner account
s.FundAcc(owner, coinsToAdd)

// Save the gas meter before the method call
existingGasConsumed := s.Ctx.GasMeter().GasConsumed()

// AddToGaugeRewards
err := s.App.IncentivesKeeper.AddToGaugeRewards(s.Ctx, owner, coinsToAdd, 1)
s.Require().NoError(err)

// Min expected gas consumed
baseGasFee := s.App.IncentivesKeeper.GetParams(s.Ctx).BaseGasFeeForAddRewardToGauge
minimumGasConsumed := baseGasFee * uint64(len(gaugeCoins)+len(coinsToAdd))

// Ensure that at least the minimum amount of gas was charged (based on number of additional gauge coins)
gasConsumed := s.Ctx.GasMeter().GasConsumed() - existingGasConsumed
fmt.Println(gasConsumed, minimumGasConsumed)
s.Require().True(gasConsumed >= minimumGasConsumed)

// Existing coins gets added to the module when we create gauge and add to gauge
expectedCoins := existingGaugeCoins.Add(coinsToAdd...)

// Check module account balance, should go up
balance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName))
s.Require().Equal(expectedCoins, balance)

// Check gauge coins should go up
gauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, 1)
s.Require().NoError(err)

s.Require().Equal(expectedCoins, gauge.Coins)
})
}
14 changes: 8 additions & 6 deletions x/incentives/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"
"time"

"cosmossdk.io/math"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil"
Expand All @@ -27,7 +28,9 @@ func TestIncentivesExportGenesis(t *testing.T) {
// create an address and fund with coins
addr := sdk.AccAddress([]byte("addr1---------------"))
coins := sdk.Coins{sdk.NewInt64Coin("stake", 10000)}
err := bankutil.FundAccount(app.BankKeeper, ctx, addr, coins)
// balance including fees
addrCoins := coins.Add(sdk.NewCoin("stake", types.DYM.MulRaw(1000)))
err := bankutil.FundAccount(app.BankKeeper, ctx, addr, addrCoins)
require.NoError(t, err)

// mints LP tokens and send to address created earlier
Expand Down Expand Up @@ -96,11 +99,10 @@ func TestIncentivesInitGenesis(t *testing.T) {
// initialize genesis with specified parameter, the gauge created earlier, and lockable durations
app.IncentivesKeeper.InitGenesis(ctx, types.GenesisState{
Params: types.Params{
DistrEpochIdentifier: "week",
CreateGaugeFee: sdk.ZeroInt(),
AddToGaugeFee: sdk.ZeroInt(),
BaseGasFeeForCreateGauge: 0,
BaseGasFeeForAddRewardToGauge: 0,
DistrEpochIdentifier: "week",
CreateGaugeBaseFee: math.ZeroInt(),
AddToGaugeBaseFee: math.ZeroInt(),
AddDenomFee: math.ZeroInt(),
},
Gauges: []types.Gauge{gauge},
LockableDurations: []time.Duration{
Expand Down
9 changes: 0 additions & 9 deletions x/incentives/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ func (server msgServer) CreateGauge(goCtx context.Context, msg *types.MsgCreateG
return nil, err
}

createGaugeFee := server.keeper.GetParams(ctx).CreateGaugeFee
if err := server.keeper.chargeFeeIfSufficientFeeDenomBalance(ctx, owner, createGaugeFee, msg.Coins); err != nil {
return nil, err
}

gaugeID, err := server.keeper.CreateGauge(ctx, msg.IsPerpetual, owner, msg.Coins, msg.DistributeTo, msg.StartTime, msg.NumEpochsPaidOver)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
Expand All @@ -63,10 +58,6 @@ func (server msgServer) AddToGauge(goCtx context.Context, msg *types.MsgAddToGau
return nil, err
}

addToGaugeFee := server.keeper.GetParams(ctx).AddToGaugeFee
if err := server.keeper.chargeFeeIfSufficientFeeDenomBalance(ctx, owner, addToGaugeFee, msg.Rewards); err != nil {
return nil, err
}
err = server.keeper.AddToGaugeRewards(ctx, owner, msg.Rewards, msg.GaugeId)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
Expand Down
Loading

0 comments on commit 380559f

Please sign in to comment.