Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(incentives): create gauge and add to gauge fee charge (backport #2227) #2237

Merged
merged 3 commits into from
Jul 26, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
appKeepers.BankKeeper,
appKeepers.LockupKeeper,
appKeepers.EpochsKeeper,
appKeepers.DistrKeeper,
)

appKeepers.SuperfluidKeeper = superfluidkeeper.NewKeeper(
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ require (
github.com/coinbase/rosetta-sdk-go v0.7.0 // indirect
github.com/confio/ics23/go v0.7.0 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/cosmos/btcutil v1.0.4 // indirect
github.com/cosmos/btcutil v1.0.4
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect
github.com/cosmos/ledger-go v0.9.2 // indirect
Expand Down
10 changes: 8 additions & 2 deletions x/incentives/keeper/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"github.com/osmosis-labs/osmosis/v10/x/incentives/types"
)

func (k Keeper) AddGaugeRefByKey(ctx sdk.Context, key []byte, guageID uint64) error {
return k.addGaugeRefByKey(ctx, key, guageID)
// AddGaugeRefByKey appends the provided gauge ID into an array associated with the provided key.
func (k Keeper) AddGaugeRefByKey(ctx sdk.Context, key []byte, gaugeID uint64) error {
return k.addGaugeRefByKey(ctx, key, gaugeID)
}

func (k Keeper) DeleteGaugeRefByKey(ctx sdk.Context, key []byte, guageID uint64) error {
Expand All @@ -29,3 +30,8 @@ func (k Keeper) MoveUpcomingGaugeToActiveGauge(ctx sdk.Context, gauge types.Gaug
func (k Keeper) MoveActiveGaugeToFinishedGauge(ctx sdk.Context, gauge types.Gauge) error {
return k.moveActiveGaugeToFinishedGauge(ctx, gauge)
}

// ChargeFeeIfSufficientFeeDenomBalance see chargeFeeIfSufficientFeeDenomBalance spec.
func (k Keeper) ChargeFeeIfSufficientFeeDenomBalance(ctx sdk.Context, address sdk.AccAddress, fee sdk.Int, gaugeCoins sdk.Coins) error {
return k.chargeFeeIfSufficientFeeDenomBalance(ctx, address, fee, gaugeCoins)
}
19 changes: 19 additions & 0 deletions x/incentives/keeper/gauge.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"strings"
"time"

sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/gogo/protobuf/proto"
db "github.com/tendermint/tm-db"

appparams "github.com/osmosis-labs/osmosis/v10/app/params"
epochtypes "github.com/osmosis-labs/osmosis/v10/x/epochs/types"
"github.com/osmosis-labs/osmosis/v10/x/incentives/types"
lockuptypes "github.com/osmosis-labs/osmosis/v10/x/lockup/types"
Expand Down Expand Up @@ -281,3 +283,20 @@ func (k Keeper) GetEpochInfo(ctx sdk.Context) epochtypes.EpochInfo {
params := k.GetParams(ctx)
return k.ek.GetEpochInfo(ctx, params.DistrEpochIdentifier)
}

// chargeFeeIfSufficientFeeDenomBalance charges fee in the base denom on the address if the address has
// balance that is less than fee + amount of the coin from gaugeCoins that is of base denom.
// gaugeCoins might not have a coin of tx base denom. In that case, fee is only compared to balance.
// The fee is sent to the community pool.
// Returns nil on success, error otherwise.
func (k Keeper) chargeFeeIfSufficientFeeDenomBalance(ctx sdk.Context, address sdk.AccAddress, fee sdk.Int, gaugeCoins sdk.Coins) (err error) {
totalCost := gaugeCoins.AmountOf(appparams.BaseCoinUnit).Add(fee)
accountBalance := k.bk.GetBalance(ctx, address, appparams.BaseCoinUnit).Amount
if accountBalance.LT(totalCost) {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "account's balance of %s (%s) is less than the total cost of the message (%s)", appparams.BaseCoinUnit, accountBalance, totalCost)
}
if err := k.dk.FundCommunityPool(ctx, sdk.NewCoins(sdk.NewCoin(appparams.BaseCoinUnit, fee)), address); err != nil {
return err
}
return nil
}
96 changes: 96 additions & 0 deletions x/incentives/keeper/gauge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
"time"

appparams "github.com/osmosis-labs/osmosis/v10/app/params"
"github.com/osmosis-labs/osmosis/v10/x/incentives/types"
lockuptypes "github.com/osmosis-labs/osmosis/v10/x/lockup/types"

Expand Down Expand Up @@ -310,3 +311,98 @@ func (suite *KeeperTestSuite) TestGaugesByDenom() {
testGaugeByDenom(true)
testGaugeByDenom(false)
}

func (suite *KeeperTestSuite) TestChargeFeeIfSufficientFeeDenomBalance() {
const baseFee = int64(100)

testcases := map[string]struct {
accountBalanceToFund sdk.Coin
feeToCharge int64
gaugeCoins sdk.Coins

expectError bool
}{
"fee + base denom gauge coin == acount balance, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee)),
feeToCharge: baseFee / 2,
gaugeCoins: sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee/2))),
},
"fee + base denom gauge coin < acount balance, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee)),
feeToCharge: baseFee/2 - 1,
gaugeCoins: sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee/2))),
},
"fee + base denom gauge coin > acount balance, error": {
accountBalanceToFund: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseFee)),
feeToCharge: baseFee/2 + 1,
gaugeCoins: sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee/2))),

expectError: true,
},
"fee + base denom gauge coin < acount balance, custom values, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(11793193112)),
feeToCharge: 55,
gaugeCoins: sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(328812))),
},
"account funded with coins other than base denom, error": {
accountBalanceToFund: sdk.NewCoin("usdc", sdk.NewInt(baseFee)),
feeToCharge: baseFee,
gaugeCoins: sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee/2))),

expectError: true,
},
"fee == account balance, no gauge coins, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee)),
feeToCharge: baseFee,
},
"gauge coins == account balance, no fee, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee)),
gaugeCoins: sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee))),
},
"fee == account balance, gauge coins in denom other than base, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee)),
feeToCharge: baseFee,
gaugeCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(baseFee*2))),
},
"fee + gauge coins == account balance, multiple gauge coins, one in denom other than base, success": {
accountBalanceToFund: sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee)),
feeToCharge: baseFee / 2,
gaugeCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(baseFee*2)), sdk.NewCoin(appparams.DefaultBondDenom, sdk.NewInt(baseFee/2))),
},
}

for name, tc := range testcases {
suite.Run(name, func() {
suite.SetupTest()

testAccount := suite.TestAccs[0]

ctx := suite.Ctx
incentivesKeepers := suite.App.IncentivesKeeper
bankKeeper := suite.App.BankKeeper

// Pre-fund account.
suite.FundAcc(testAccount, sdk.NewCoins(tc.accountBalanceToFund))

oldBalanceAmount := bankKeeper.GetBalance(ctx, testAccount, appparams.DefaultBondDenom).Amount

// System under test.
err := incentivesKeepers.ChargeFeeIfSufficientFeeDenomBalance(ctx, testAccount, sdk.NewInt(tc.feeToCharge), tc.gaugeCoins)

// Assertions.
newBalanceAmount := bankKeeper.GetBalance(ctx, testAccount, appparams.DefaultBondDenom).Amount
if tc.expectError {
suite.Require().Error(err)

// check account balance unchanged
suite.Require().Equal(oldBalanceAmount, newBalanceAmount)
} else {
suite.Require().NoError(err)

// check account balance changed.
expectedNewBalanceAmount := oldBalanceAmount.Sub(sdk.NewInt(tc.feeToCharge))
suite.Require().Equal(expectedNewBalanceAmount.String(), newBalanceAmount.String())
}
})
}
}
5 changes: 4 additions & 1 deletion x/incentives/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ type Keeper struct {
bk types.BankKeeper
lk types.LockupKeeper
ek types.EpochKeeper
dk types.DistrKeeper
}

func NewKeeper(cdc codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, bk types.BankKeeper, lk types.LockupKeeper, ek types.EpochKeeper) *Keeper {
// NewKeeper returns a new instance of the incentive module keeper struct.
func NewKeeper(cdc codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, bk types.BankKeeper, lk types.LockupKeeper, ek types.EpochKeeper, dk types.DistrKeeper) *Keeper {
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
}
Expand All @@ -35,6 +37,7 @@ func NewKeeper(cdc codec.Codec, storeKey sdk.StoreKey, paramSpace paramtypes.Sub
bk: bk,
lk: lk,
ek: ek,
dk: dk,
}
}

Expand Down
8 changes: 8 additions & 0 deletions x/incentives/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ func (server msgServer) CreateGauge(goCtx context.Context, msg *types.MsgCreateG
return nil, err
}

if err := server.keeper.chargeFeeIfSufficientFeeDenomBalance(ctx, owner, types.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 @@ -51,6 +55,10 @@ func (server msgServer) AddToGauge(goCtx context.Context, msg *types.MsgAddToGau
if err != nil {
return nil, err
}

if err := server.keeper.chargeFeeIfSufficientFeeDenomBalance(ctx, owner, types.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