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

[CORE-824] Implement keeper methods for LimitParams and DenomCapacity #877

Merged
merged 5 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion proto/dydxprotocol/ibcratelimit/limit_params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ message LimitParams {
string denom = 1;
// limiters is a list of rate-limiters on this denom. All limiters
// must be satified for a withdrawal to proceed.
repeated Limiter limiters = 2;
repeated Limiter limiters = 2 [ (gogoproto.nullable) = false ];
}

// Limiter defines one rate-limiter on a specfic denom.
Expand Down
21 changes: 21 additions & 0 deletions protocol/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ import (
feetiersmodule "github.com/dydxprotocol/v4-chain/protocol/x/feetiers"
feetiersmodulekeeper "github.com/dydxprotocol/v4-chain/protocol/x/feetiers/keeper"
feetiersmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/feetiers/types"
ibcratelimitmodulekeeper "github.com/dydxprotocol/v4-chain/protocol/x/ibcratelimit/keeper"
ibcratelimitmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/ibcratelimit/types"
perpetualsmodule "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals"
perpetualsmodulekeeper "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/keeper"
perpetualsmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
Expand All @@ -152,6 +154,7 @@ import (
rewardsmodule "github.com/dydxprotocol/v4-chain/protocol/x/rewards"
rewardsmodulekeeper "github.com/dydxprotocol/v4-chain/protocol/x/rewards/keeper"
rewardsmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/rewards/types"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove extra line

sendingmodule "github.com/dydxprotocol/v4-chain/protocol/x/sending"
sendingmodulekeeper "github.com/dydxprotocol/v4-chain/protocol/x/sending/keeper"
sendingmoduletypes "github.com/dydxprotocol/v4-chain/protocol/x/sending/types"
Expand Down Expand Up @@ -237,6 +240,7 @@ type App struct {
IBCKeeper *ibckeeper.Keeper
EvidenceKeeper evidencekeeper.Keeper
TransferKeeper ibctransferkeeper.Keeper
IBCRateLimitKeeper ibcratelimitmodulekeeper.Keeper
FeeGrantKeeper feegrantkeeper.Keeper
ConsensusParamsKeeper consensusparamkeeper.Keeper

Expand Down Expand Up @@ -343,6 +347,7 @@ func New(
distrtypes.StoreKey, slashingtypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,
ibcexported.StoreKey, ibctransfertypes.StoreKey,
ibcratelimitmoduletypes.StoreKey,
evidencetypes.StoreKey,
capabilitytypes.StoreKey,
pricesmoduletypes.StoreKey,
Expand Down Expand Up @@ -533,6 +538,18 @@ func New(
transferModule := transfer.NewAppModule(app.TransferKeeper)
transferIBCModule := transfer.NewIBCModule(app.TransferKeeper)

app.IBCRateLimitKeeper = *ibcratelimitmodulekeeper.NewKeeper(
appCodec,
keys[ibcratelimitmoduletypes.StoreKey],
// set the governance and delaymsg module accounts as the authority for conducting upgrades
[]string{
lib.GovModuleAddress.String(),
delaymsgmoduletypes.ModuleAddress.String(),
},
)

// TODO(CORE-834): Add IBCRatelimitKeeper to the IBC transfer stack.

// Create static IBC router, add transfer route, then set and seal it
ibcRouter := ibcporttypes.NewRouter()
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule)
Expand Down Expand Up @@ -972,6 +989,7 @@ func New(
stakingtypes.ModuleName,
ibcexported.ModuleName,
ibctransfertypes.ModuleName,
ibcratelimitmoduletypes.ModuleName,
authtypes.ModuleName,
banktypes.ModuleName,
govtypes.ModuleName,
Expand Down Expand Up @@ -1014,6 +1032,7 @@ func New(
upgradetypes.ModuleName,
ibcexported.ModuleName,
ibctransfertypes.ModuleName,
ibcratelimitmoduletypes.ModuleName,
consensusparamtypes.ModuleName,
pricesmoduletypes.ModuleName,
assetsmoduletypes.ModuleName,
Expand Down Expand Up @@ -1052,6 +1071,7 @@ func New(
paramstypes.ModuleName,
upgradetypes.ModuleName,
ibctransfertypes.ModuleName,
ibcratelimitmoduletypes.ModuleName,
feegrant.ModuleName,
consensusparamtypes.ModuleName,
pricesmoduletypes.ModuleName,
Expand Down Expand Up @@ -1087,6 +1107,7 @@ func New(
paramstypes.ModuleName,
upgradetypes.ModuleName,
ibctransfertypes.ModuleName,
ibcratelimitmoduletypes.ModuleName,
feegrant.ModuleName,
consensusparamtypes.ModuleName,
pricesmoduletypes.ModuleName,
Expand Down
207 changes: 207 additions & 0 deletions protocol/x/ibcratelimit/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,26 @@ package keeper

import (
"fmt"
"math/big"

errorsmod "cosmossdk.io/errors"
sdklog "cosmossdk.io/log"
"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dydxprotocol/v4-chain/protocol/dtypes"
"github.com/dydxprotocol/v4-chain/protocol/lib"
"github.com/dydxprotocol/v4-chain/protocol/x/ibcratelimit/types"
)

var (
// TempTVLPlacerholder is a placeholder value for TVL.
// TODO(CORE-836): Remove this after `GetBaseline` is fully implemented.
TempTVLPlacerholder = big.NewInt(20_000_000_000_000)
)

type (
Keeper struct {
cdc codec.BinaryCodec
Expand All @@ -36,6 +46,203 @@ func NewKeeper(
}
}

// ProcessWithdrawal processes an outbound IBC transfer,
// by updating the capacity lists for the denom.
func (k Keeper) ProcessWithdrawal(
ctx sdk.Context,
denom string,
amount *big.Int,
) error {
denomCapacity := k.GetDenomCapacity(ctx, denom)

newCapacityList := make([]dtypes.SerializableInt,
0,
len(denomCapacity.CapacityList),
)

for i, capacity := range denomCapacity.CapacityList {
// Check that the withdrawal amount does not exceed each capacity.
if capacity.BigInt().Cmp(amount) < 0 {
return errorsmod.Wrapf(
types.ErrWithdrawalExceedsCapacity,
"denom = %v, capacity(index: %v) = %v, amount = %v",
denom,
i,
capacity.BigInt(),
amount,
)
}

// Debit each capacity in the list by the amount of withdrawal.
newCapacityList[i] = dtypes.NewIntFromBigInt(
new(big.Int).Sub(
capacity.BigInt(),
amount,
),
)
}

k.SetDenomCapacity(ctx, types.DenomCapacity{
Denom: denom,
CapacityList: newCapacityList,
})

return nil
}

// ProcessDeposit processes a inbound IBC transfer,
// by updating the capacity lists for the denom.
func (k Keeper) ProcessDeposit(
ctx sdk.Context,
denom string,
amount *big.Int,
) {
denomCapacity := k.GetDenomCapacity(ctx, denom)

newCapacityList := make([]dtypes.SerializableInt,
0,
len(denomCapacity.CapacityList),
)

// Credit each capacity in the list by the amount of deposit.
for i, capacity := range denomCapacity.CapacityList {
newCapacityList[i] = dtypes.NewIntFromBigInt(
new(big.Int).Add(
capacity.BigInt(),
amount,
),
)
}

k.SetDenomCapacity(ctx, types.DenomCapacity{
Denom: denom,
CapacityList: newCapacityList,
})
}

// GetBaseline returns the current capacity baseline for the given limiter.
// `baseline` formula:
//
// baseline = max(baseline_minimum, baseline_tvl_ppm * current_tvl)
func (k Keeper) GetBaseline(
ctx sdk.Context,
denom string,
limiter types.Limiter,
) *big.Int {
// Get the current TVL.
// TODO(CORE-836): Query bank Keeper to get current supply of the token.
currentTVL := TempTVLPlacerholder

return lib.BigMax(
limiter.BaselineMinimum.BigInt(),
lib.BigIntMulPpm(
currentTVL,
limiter.BaselineTvlPpm,
),
)
}

// SetLimitParams sets `LimitParams` for the given denom.
// Also overwrites the existing `DenomCapacity` object for the denom with a default `capacity_list` of the
// same length as the `limiters` list. Each `capacity` is initialized to the current baseline.
func (k Keeper) SetLimitParams(
ctx sdk.Context,
limitParams types.LimitParams,
) {
limitParamsStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.LimitParamsKeyPrefix))
denomCapacityStore := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.DenomCapacityKeyPrefix))

denomKey := []byte(limitParams.Denom)
// If the length of input limit params is zero, then remove both the
// limit params and the denom capacity in state.
if len(limitParams.Limiters) == 0 {
if limitParamsStore.Has(denomKey) {
limitParamsStore.Delete(denomKey)
}
if denomCapacityStore.Has(denomKey) {
denomCapacityStore.Delete(denomKey)
}
return
}

// Initialize the capacity list with the current baseline.
newCapacityList := make([]dtypes.SerializableInt, len(limitParams.Limiters))
for i, limiter := range limitParams.Limiters {
newCapacityList[i] = dtypes.NewIntFromBigInt(
k.GetBaseline(ctx, limitParams.Denom, limiter),
)
}
// Set correspondong `DenomCapacity` in state.
k.SetDenomCapacity(ctx, types.DenomCapacity{
Denom: limitParams.Denom,
CapacityList: newCapacityList,
})

b := k.cdc.MustMarshal(&limitParams)
limitParamsStore.Set(denomKey, b)
}

// GetLimitParams returns `LimitParams` for the given denom.
func (k Keeper) GetLimitParams(
ctx sdk.Context,
denom string,
) (val types.LimitParams) {
// Check state for the LimitParams.
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.LimitParamsKeyPrefix))
b := store.Get([]byte(denom))

// If LimitParams does not exist in state, return a default value.
if b == nil {
return types.LimitParams{
Denom: denom,
}
}

// If LimitParams does exist in state, unmarshall and return the value.
k.cdc.MustUnmarshal(b, &val)
return val
}

// SetDenomCapacity sets `DenomCapacity` for the given denom.
func (k Keeper) SetDenomCapacity(
ctx sdk.Context,
denomCapacity types.DenomCapacity,
) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.DenomCapacityKeyPrefix))

key := []byte(denomCapacity.Denom)
// If there's no capacity entry to set, delete the key.
if len(denomCapacity.CapacityList) == 0 {
if store.Has(key) {
store.Delete(key)
}
} else {
b := k.cdc.MustMarshal(&denomCapacity)
store.Set(key, b)
}
}

// GetDenomCapacity returns `DenomCapacity` for the given denom.
func (k Keeper) GetDenomCapacity(
ctx sdk.Context,
denom string,
) (val types.DenomCapacity) {
// Check state for the DenomCapacity.
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.DenomCapacityKeyPrefix))
b := store.Get([]byte(denom))

// If DenomCapacity does not exist in state, return a default value.
if b == nil {
return types.DenomCapacity{
Denom: denom,
}
}

// If DenomCapacity does exist in state, unmarshall and return the value.
k.cdc.MustUnmarshal(b, &val)
return val
}

func (k Keeper) HasAuthority(authority string) bool {
_, ok := k.authorities[authority]
return ok
Expand Down
Loading
Loading