Skip to content

Commit

Permalink
feat(lockup): added const fee for locking tokens (#1543)
Browse files Browse the repository at this point in the history
  • Loading branch information
keruch authored Nov 25, 2024
1 parent 6734dc3 commit 93b6385
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 8 deletions.
15 changes: 8 additions & 7 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,6 @@ func (a *AppKeepers) InitKeepers(

// Osmosis keepers

a.LockupKeeper = lockupkeeper.NewKeeper(
a.keys[lockuptypes.StoreKey],
a.GetSubspace(lockuptypes.ModuleName),
a.AccountKeeper,
a.BankKeeper,
)

a.EpochsKeeper = epochskeeper.NewKeeper(
a.keys[epochstypes.StoreKey],
)
Expand Down Expand Up @@ -337,6 +330,14 @@ func (a *AppKeepers) InitKeepers(
a.GAMMKeeper.SetPoolManager(a.PoolManagerKeeper)
a.GAMMKeeper.SetTxFees(a.TxFeesKeeper)

a.LockupKeeper = lockupkeeper.NewKeeper(
a.keys[lockuptypes.StoreKey],
a.GetSubspace(lockuptypes.ModuleName),
a.AccountKeeper,
a.BankKeeper,
a.TxFeesKeeper,
)

// Create IBC Keeper
a.IBCKeeper = ibckeeper.NewKeeper(
appCodec,
Expand Down
4 changes: 3 additions & 1 deletion x/lockup/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ type Keeper struct {

ak types.AccountKeeper
bk types.BankKeeper
tk types.TxFeesKeeper
}

// NewKeeper returns an instance of Keeper.
func NewKeeper(storeKey stroretypes.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper) *Keeper {
func NewKeeper(storeKey stroretypes.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, tk types.TxFeesKeeper) *Keeper {
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
Expand All @@ -35,6 +36,7 @@ func NewKeeper(storeKey stroretypes.StoreKey, paramSpace paramtypes.Subspace, ak
paramSpace: paramSpace,
ak: ak,
bk: bk,
tk: tk,
}
}

Expand Down
29 changes: 29 additions & 0 deletions x/lockup/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func (server msgServer) LockTokens(goCtx context.Context, msg *types.MsgLockToke
return nil, err
}

// Charge fess for locking tokens
if err = server.keeper.ChargeLockFee(ctx, owner, types.DefaultLockFee, msg.Coins); err != nil {
return nil, fmt.Errorf("charge gauge fee: %w", err)
}

// check if there's an existing lock from the same owner with the same duration.
// If so, simply add tokens to the existing lock.
lockExists := server.keeper.HasLock(ctx, owner, msg.Coins[0].Denom, msg.Duration)
Expand Down Expand Up @@ -217,3 +222,27 @@ func (server msgServer) ForceUnlock(goCtx context.Context, msg *types.MsgForceUn

return &types.MsgForceUnlockResponse{Success: true}, nil
}

// ChargeLockFee deducts a fee in the base denom from the specified address. The total cost is calculated as the sum
// of the fee and the amount of the base denom coin from lockCoins. If the account's balance is less than the total
// cost, the error is returned. Otherwise, the fee is charged from the payer and sent to x/txfees to be burned.
func (k Keeper) ChargeLockFee(ctx sdk.Context, payer sdk.AccAddress, fee sdk.Int, lockCoins sdk.Coins) (err error) {
var feeDenom string
if k.tk == nil {
feeDenom, err = sdk.GetBaseDenom()
} else {
feeDenom, err = k.tk.GetBaseDenom(ctx)
}
if err != nil {
return err
}

totalCost := lockCoins.AmountOf(feeDenom).Add(fee)
accountBalance := k.bk.GetBalance(ctx, payer, feeDenom).Amount

if accountBalance.LT(totalCost) {
return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "account's balance is less than the total cost of the message: balance: %s%s, total cost: %s%s", accountBalance, feeDenom, totalCost, feeDenom)
}

return k.tk.ChargeFeesFromPayer(ctx, payer, sdk.NewCoin(feeDenom, fee), nil)
}
18 changes: 18 additions & 0 deletions x/lockup/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func (suite *KeeperTestSuite) TestMsgLockTokens() {
suite.SetupTest()

suite.FundAcc(test.param.lockOwner, test.param.coinsInOwnerAddress)
// fund address with lock fee
baseDenom, _ := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx)
suite.FundAcc(test.param.lockOwner, sdk.NewCoins(sdk.NewCoin(baseDenom, types.DefaultLockFee)))

msgServer := keeper.NewMsgServerImpl(suite.App.LockupKeeper)
c := sdk.WrapSDKContext(suite.Ctx)
Expand All @@ -75,6 +78,8 @@ func (suite *KeeperTestSuite) TestMsgLockTokens() {

// add more tokens to lock via LockTokens
suite.FundAcc(test.param.lockOwner, test.param.coinsInOwnerAddress)
// fund address with lock fee
suite.FundAcc(test.param.lockOwner, sdk.NewCoins(sdk.NewCoin(baseDenom, types.DefaultLockFee)))

_, err = msgServer.LockTokens(sdk.WrapSDKContext(suite.Ctx), types.NewMsgLockTokens(test.param.lockOwner, locks[0].Duration, test.param.coinsToLock))
suite.Require().NoError(err)
Expand Down Expand Up @@ -156,6 +161,9 @@ func (suite *KeeperTestSuite) TestMsgBeginUnlocking() {
suite.SetupTest()

suite.FundAcc(test.param.lockOwner, test.param.coinsInOwnerAddress)
// fund address with lock fee
baseDenom, _ := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx)
suite.FundAcc(test.param.lockOwner, sdk.NewCoins(sdk.NewCoin(baseDenom, types.DefaultLockFee)))

msgServer := keeper.NewMsgServerImpl(suite.App.LockupKeeper)
goCtx := sdk.WrapSDKContext(suite.Ctx)
Expand Down Expand Up @@ -209,6 +217,9 @@ func (suite *KeeperTestSuite) TestMsgBeginUnlockingAll() {
suite.SetupTest()

suite.FundAcc(test.param.lockOwner, test.param.coinsInOwnerAddress)
// fund address with lock fee
baseDenom, _ := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx)
suite.FundAcc(test.param.lockOwner, sdk.NewCoins(sdk.NewCoin(baseDenom, types.DefaultLockFee)))

msgServer := keeper.NewMsgServerImpl(suite.App.LockupKeeper)
c := sdk.WrapSDKContext(suite.Ctx)
Expand Down Expand Up @@ -268,6 +279,9 @@ func (suite *KeeperTestSuite) TestMsgEditLockup() {

err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, test.param.lockOwner, test.param.coinsToLock)
suite.Require().NoError(err)
// fund address with lock fee
baseDenom, _ := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx)
suite.FundAcc(test.param.lockOwner, sdk.NewCoins(sdk.NewCoin(baseDenom, types.DefaultLockFee)))

msgServer := keeper.NewMsgServerImpl(suite.App.LockupKeeper)
c := sdk.WrapSDKContext(suite.Ctx)
Expand Down Expand Up @@ -351,6 +365,10 @@ func (suite *KeeperTestSuite) TestMsgForceUnlock() {
coinsToLock := sdk.Coins{sdk.NewCoin(poolDenom, defaultLockAmount)}
suite.FundAcc(addr1, coinsToLock)

// fund address with lock fee
baseDenom, _ := suite.App.TxFeesKeeper.GetBaseDenom(suite.Ctx)
suite.FundAcc(addr1, sdk.NewCoins(sdk.NewCoin(baseDenom, types.DefaultLockFee)))

unbondingDuration := suite.App.StakingKeeper.GetParams(suite.Ctx).UnbondingTime
resp, err := msgServer.LockTokens(c, types.NewMsgLockTokens(addr1, unbondingDuration, coinsToLock))
suite.Require().NoError(err)
Expand Down
7 changes: 7 additions & 0 deletions x/lockup/types/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package types

import (
"github.com/dymensionxyz/dymension/v3/x/common/types"
)

var DefaultLockFee = types.DYM.QuoRaw(4) // 0.25 DYM
7 changes: 7 additions & 0 deletions x/lockup/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ type AccountKeeper interface {
// BankKeeper defines the expected interface needed to retrieve account balances.
type BankKeeper interface {
GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin

SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
}

// TxFeesKeeper defines the expected interface needed to managing transaction fees.
type TxFeesKeeper interface {
GetBaseDenom(ctx sdk.Context) (denom string, err error)
ChargeFeesFromPayer(ctx sdk.Context, payer sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error
}

0 comments on commit 93b6385

Please sign in to comment.