Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,23 @@ export interface UserStatsSDKType {

affiliate_30d_referred_volume_quote_quantums: Long;
}
/** CachedStakeAmount stores the last calculated total staked amount for address */
/** CachedStakedBaseTokens stores the last calculated total staked base tokens */

export interface CachedStakeAmount {
/** Last calculated total staked amount by the delegator (in coin amount). */
stakedAmount: Uint8Array;
export interface CachedStakedBaseTokens {
/** Last calculated total staked base tokens by the delegator. */
stakedBaseTokens: Uint8Array;
/**
* Block time at which the calculation is cached (in Unix Epoch seconds)
* Rounded down to nearest second.
*/

cachedAt: Long;
}
/** CachedStakeAmount stores the last calculated total staked amount for address */
/** CachedStakedBaseTokens stores the last calculated total staked base tokens */

export interface CachedStakeAmountSDKType {
/** Last calculated total staked amount by the delegator (in coin amount). */
staked_amount: Uint8Array;
export interface CachedStakedBaseTokensSDKType {
/** Last calculated total staked base tokens by the delegator. */
staked_base_tokens: Uint8Array;
/**
* Block time at which the calculation is cached (in Unix Epoch seconds)
* Rounded down to nearest second.
Expand Down Expand Up @@ -573,17 +573,17 @@ export const UserStats = {

};

function createBaseCachedStakeAmount(): CachedStakeAmount {
function createBaseCachedStakedBaseTokens(): CachedStakedBaseTokens {
return {
stakedAmount: new Uint8Array(),
stakedBaseTokens: new Uint8Array(),
cachedAt: Long.ZERO
};
}

export const CachedStakeAmount = {
encode(message: CachedStakeAmount, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.stakedAmount.length !== 0) {
writer.uint32(10).bytes(message.stakedAmount);
export const CachedStakedBaseTokens = {
encode(message: CachedStakedBaseTokens, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.stakedBaseTokens.length !== 0) {
writer.uint32(10).bytes(message.stakedBaseTokens);
}

if (!message.cachedAt.isZero()) {
Expand All @@ -593,17 +593,17 @@ export const CachedStakeAmount = {
return writer;
},

decode(input: _m0.Reader | Uint8Array, length?: number): CachedStakeAmount {
decode(input: _m0.Reader | Uint8Array, length?: number): CachedStakedBaseTokens {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseCachedStakeAmount();
const message = createBaseCachedStakedBaseTokens();

while (reader.pos < end) {
const tag = reader.uint32();

switch (tag >>> 3) {
case 1:
message.stakedAmount = reader.bytes();
message.stakedBaseTokens = reader.bytes();
break;

case 2:
Expand All @@ -619,9 +619,9 @@ export const CachedStakeAmount = {
return message;
},

fromPartial(object: DeepPartial<CachedStakeAmount>): CachedStakeAmount {
const message = createBaseCachedStakeAmount();
message.stakedAmount = object.stakedAmount ?? new Uint8Array();
fromPartial(object: DeepPartial<CachedStakedBaseTokens>): CachedStakedBaseTokens {
const message = createBaseCachedStakedBaseTokens();
message.stakedBaseTokens = object.stakedBaseTokens ?? new Uint8Array();
message.cachedAt = object.cachedAt !== undefined && object.cachedAt !== null ? Long.fromValue(object.cachedAt) : Long.ZERO;
return message;
}
Expand Down
8 changes: 4 additions & 4 deletions proto/dydxprotocol/stats/stats.proto
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ message UserStats {
uint64 affiliate_30d_referred_volume_quote_quantums = 4;
}

// CachedStakeAmount stores the last calculated total staked amount for address
message CachedStakeAmount {
// Last calculated total staked amount by the delegator (in coin amount).
bytes staked_amount = 1 [
// CachedStakedBaseTokens stores the last calculated total staked base tokens
message CachedStakedBaseTokens {
// Last calculated total staked base tokens by the delegator.
bytes staked_base_tokens = 1 [
(gogoproto.customtype) =
"github.com/dydxprotocol/v4-chain/protocol/dtypes.SerializableInt",
(gogoproto.nullable) = false
Expand Down
8 changes: 4 additions & 4 deletions protocol/lib/metrics/metric_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const (
ClobRateLimitPlaceOrderCount = "clob_rate_limit_place_order_count"
ClobRateLimitCancelOrderCount = "clob_rate_limit_cancel_order_count"
ClobRateLimitBatchCancelCount = "clob_rate_limit_batch_cancel_count"
StatsGetStakedAmountCacheHit = "stats_get_staked_amount_cache_hit"
StatsGetStakedAmountCacheMiss = "stats_get_staked_amount_cache_miss"
StatsGetStakedBaseTokensCacheHit = "stats_get_staked_base_tokens_cache_hit"
StatsGetStakedBaseTokensCacheMiss = "stats_get_staked_base_tokens_cache_miss"

// Gauges
InsuranceFundBalance = "insurance_fund_balance"
Expand All @@ -38,8 +38,8 @@ const (
ClobSubaccountsRequiringDeleveragingCount = "clob_subaccounts_requiring_deleveraging_count"
SendingProcessDepositToSubaccount = "sending_process_deposit_to_subaccount"
RateLimitInsufficientWithdrawalAmount = "rate_limit_insufficient_withdrawal_amount"
StatsGetStakedAmountLatencyCacheHit = "stats_get_staked_amount_latency_cache_hit"
StatsGetStakedAmountLatencyCacheMiss = "stats_get_staked_amount_latency_cache_miss"
StatsGetStakedBaseTokensLatencyCacheHit = "stats_get_staked_base_tokens_latency_cache_hit"
StatsGetStakedBaseTokensLatencyCacheMiss = "stats_get_staked_base_tokens_latency_cache_miss"

// Samples
ClobDeleverageSubaccountTotalQuoteQuantumsDistribution = "clob_deleverage_subaccount_total_quote_quantums_distribution"
Expand Down
2 changes: 1 addition & 1 deletion protocol/x/affiliates/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (k Keeper) AffiliateInfo(c context.Context,

userStats := k.statsKeeper.GetUserStats(ctx, addr.String())
referredVolume := userStats.Affiliate_30DReferredVolumeQuoteQuantums
stakedAmount := k.statsKeeper.GetStakedAmount(ctx, req.GetAddress())
stakedAmount := k.statsKeeper.GetStakedBaseTokens(ctx, req.GetAddress())

return &types.AffiliateInfoResponse{
IsWhitelisted: isWhitelisted,
Expand Down
2 changes: 1 addition & 1 deletion protocol/x/affiliates/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func TestGetTakerFeeShareViaStakedAmount(t *testing.T) {
require.Equal(t, types.DefaultAffiliateTiers.Tiers[0].TakerFeeSharePpm, feeSharePpm)

ctx = ctx.WithBlockTime(ctx.BlockTime().Add(
time.Duration(statstypes.StakedAmountCacheDurationSeconds+1) * time.Second,
time.Duration(statstypes.StakedBaseTokensCacheDurationSeconds+1) * time.Second,
))
// Add more staked amount to upgrade tier
err = stakingKeeper.SetDelegation(ctx,
Expand Down
2 changes: 1 addition & 1 deletion protocol/x/affiliates/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

type StatsKeeper interface {
GetStakedAmount(ctx sdk.Context, delegatorAddr string) *big.Int
GetStakedBaseTokens(ctx sdk.Context, delegatorAddr string) *big.Int
GetBlockStats(ctx sdk.Context) *stattypes.BlockStats
GetUserStats(ctx sdk.Context, address string) *stattypes.UserStats
SetUserStats(ctx sdk.Context, address string, userStats *stattypes.UserStats)
Expand Down
2 changes: 1 addition & 1 deletion protocol/x/feetiers/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (k Keeper) UserStakingTier(
_, userFeeTier := k.getUserFeeTier(ctx, req.Address, affiliateParameters.RefereeMinimumFeeTierIdx)

// Get user's staking info
stakedAmount := k.statsKeeper.GetStakedAmount(ctx, req.Address)
stakedAmount := k.statsKeeper.GetStakedBaseTokens(ctx, req.Address)
discountPpm := k.GetStakingDiscountPpm(ctx, userFeeTier.Name, stakedAmount)

return &types.QueryUserStakingTierResponse{
Expand Down
6 changes: 3 additions & 3 deletions protocol/x/feetiers/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,9 @@ func TestUserStakingTier(t *testing.T) {
if tc.userBondedTokens != nil {
bondedAmount = tc.userBondedTokens
}
statsKeeper.UnsafeSetCachedStakedAmount(ctx, tc.req.Address, &stattypes.CachedStakeAmount{
StakedAmount: dtypes.NewIntFromBigInt(bondedAmount),
CachedAt: ctx.BlockTime().Unix(),
statsKeeper.UnsafeSetCachedStakedBaseTokens(ctx, tc.req.Address, &stattypes.CachedStakedBaseTokens{
StakedBaseTokens: dtypes.NewIntFromBigInt(bondedAmount),
CachedAt: ctx.BlockTime().Unix(),
})
}

Expand Down
2 changes: 1 addition & 1 deletion protocol/x/feetiers/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (k Keeper) GetPerpetualFeePpm(
"error", err,
)
} else {
stakedAmount := k.statsKeeper.GetStakedAmount(ctx, address)
stakedAmount := k.statsKeeper.GetStakedBaseTokens(ctx, address)
stakingDiscountPpm := k.GetStakingDiscountPpm(ctx, userTier.Name, stakedAmount)
if stakingDiscountPpm > 0 {
// Final fee
Expand Down
6 changes: 3 additions & 3 deletions protocol/x/feetiers/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,9 @@ func TestGetPerpetualFeePpm(t *testing.T) {

// Set up user bonded tokens
if tc.userBondedTokens != nil {
statsKeeper.UnsafeSetCachedStakedAmount(ctx, tc.user, &stattypes.CachedStakeAmount{
StakedAmount: dtypes.NewIntFromBigInt(tc.userBondedTokens),
CachedAt: ctx.BlockTime().Unix(),
statsKeeper.UnsafeSetCachedStakedBaseTokens(ctx, tc.user, &stattypes.CachedStakedBaseTokens{
StakedBaseTokens: dtypes.NewIntFromBigInt(tc.userBondedTokens),
CachedAt: ctx.BlockTime().Unix(),
})
}

Expand Down
2 changes: 1 addition & 1 deletion protocol/x/feetiers/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
type StatsKeeper interface {
GetUserStats(ctx sdk.Context, address string) *statstypes.UserStats
GetGlobalStats(ctx sdk.Context) *statstypes.GlobalStats
GetStakedAmount(ctx sdk.Context, delegatorAddr string) *big.Int
GetStakedBaseTokens(ctx sdk.Context, delegatorAddr string) *big.Int
}

// VaultKeeper defines the expected vault keeper.
Expand Down
71 changes: 43 additions & 28 deletions protocol/x/stats/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,49 +294,49 @@ func (k Keeper) ExpireOldStats(ctx sdk.Context) {
k.SetStatsMetadata(ctx, metadata)
}

// GetStakedAmount returns the total staked amount for a delegator address.
// GetStakedBaseTokens returns the total staked base tokens for a delegator address.
// It maintains a cache to optimize performance. The function first checks
// if there's a cached value that hasn't expired. If found, it returns the
// cached amount. Otherwise, it calculates the staked amount by querying
// the staking keeper, caches the result, and returns the calculated amount
func (k Keeper) GetStakedAmount(ctx sdk.Context,
// the staking keeper, caches the result, and returns the calculated amount.
func (k Keeper) GetStakedBaseTokens(ctx sdk.Context,
delegatorAddr string) *big.Int {
startTime := time.Now()
stakedAmount := big.NewInt(0)
stakedBaseTokens := big.NewInt(0)
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.CachedStakeAmountKeyPrefix))
bytes := store.Get([]byte(delegatorAddr))

// return cached value if it's not expired
if bytes != nil {
var cachedStakedAmount types.CachedStakeAmount
k.cdc.MustUnmarshal(bytes, &cachedStakedAmount)
var cachedStakedBaseTokens types.CachedStakedBaseTokens
k.cdc.MustUnmarshal(bytes, &cachedStakedBaseTokens)
// sanity checks
if cachedStakedAmount.CachedAt < 0 {
panic("cachedStakedAmount.CachedAt is negative")
if cachedStakedBaseTokens.CachedAt < 0 {
panic("cachedStakedBaseTokens.CachedAt is negative")
}
if ctx.BlockTime().Unix() < 0 {
panic("Invariant violation: ctx.BlockTime().Unix() is negative")
}
if cachedStakedAmount.CachedAt < 0 {
panic("Invariant violation: cachedStakedAmount.CachedAt is negative")
if cachedStakedBaseTokens.CachedAt < 0 {
panic("Invariant violation: cachedStakedBaseTokens.CachedAt is negative")
}
if cachedStakedAmount.CachedAt > ctx.BlockTime().Unix() {
panic("Invariant violation: cachedStakedAmount.CachedAt is greater than blocktime")
if cachedStakedBaseTokens.CachedAt > ctx.BlockTime().Unix() {
panic("Invariant violation: cachedStakedBaseTokens.CachedAt is greater than blocktime")
}
if ctx.BlockTime().Unix()-cachedStakedAmount.CachedAt <= types.StakedAmountCacheDurationSeconds {
stakedAmount.Set(cachedStakedAmount.StakedAmount.BigInt())
metrics.IncrCounterWithLabels(metrics.StatsGetStakedAmountCacheHit, 1)
if ctx.BlockTime().Unix()-cachedStakedBaseTokens.CachedAt <= types.StakedBaseTokensCacheDurationSeconds {
stakedBaseTokens.Set(cachedStakedBaseTokens.StakedBaseTokens.BigInt())
metrics.IncrCounterWithLabels(metrics.StatsGetStakedBaseTokensCacheHit, 1)
telemetry.MeasureSince(
startTime,
types.ModuleName,
metrics.StatsGetStakedAmountLatencyCacheHit,
metrics.StatsGetStakedBaseTokensLatencyCacheHit,
metrics.Latency,
)
return stakedAmount
return stakedBaseTokens
}
}

metrics.IncrCounterWithLabels(metrics.StatsGetStakedAmountCacheMiss, 1)
metrics.IncrCounterWithLabels(metrics.StatsGetStakedBaseTokensCacheMiss, 1)

// calculate staked amount
delegator, err := sdk.AccAddressFromBech32(delegatorAddr)
Expand All @@ -350,26 +350,41 @@ func (k Keeper) GetStakedAmount(ctx sdk.Context,
}

for _, delegation := range delegations {
stakedAmount.Add(stakedAmount, delegation.GetShares().RoundInt().BigInt())
// Get the validator to convert shares to tokens
valAddr, err := sdk.ValAddressFromBech32(delegation.GetValidatorAddr())
if err != nil {
// If invalid validator address, skip this delegation
continue
}

validator, err := k.stakingKeeper.GetValidator(ctx, valAddr)
if err != nil {
// If validator not found, skip this delegation
continue
}

// Convert shares to tokens using validator exchange rate
tokens := validator.TokensFromShares(delegation.GetShares())
stakedBaseTokens.Add(stakedBaseTokens, tokens.RoundInt().BigInt())
}

// update cache
cachedStakedAmount := types.CachedStakeAmount{
StakedAmount: dtypes.NewIntFromBigInt(stakedAmount),
CachedAt: ctx.BlockTime().Unix(),
cachedStakedBaseTokens := types.CachedStakedBaseTokens{
StakedBaseTokens: dtypes.NewIntFromBigInt(stakedBaseTokens),
CachedAt: ctx.BlockTime().Unix(),
}
store.Set([]byte(delegatorAddr), k.cdc.MustMarshal(&cachedStakedAmount))
store.Set([]byte(delegatorAddr), k.cdc.MustMarshal(&cachedStakedBaseTokens))
telemetry.MeasureSince(
startTime,
types.ModuleName,
metrics.StatsGetStakedAmountLatencyCacheMiss,
metrics.StatsGetStakedBaseTokensLatencyCacheMiss,
metrics.Latency,
)
return stakedAmount
return stakedBaseTokens
}

func (k Keeper) UnsafeSetCachedStakedAmount(ctx sdk.Context, delegatorAddr string,
cachedStakedAmount *types.CachedStakeAmount) {
func (k Keeper) UnsafeSetCachedStakedBaseTokens(ctx sdk.Context, delegatorAddr string,
cachedStakedBaseTokens *types.CachedStakedBaseTokens) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.CachedStakeAmountKeyPrefix))
store.Set([]byte(delegatorAddr), k.cdc.MustMarshal(cachedStakedAmount))
store.Set([]byte(delegatorAddr), k.cdc.MustMarshal(cachedStakedBaseTokens))
}
Loading
Loading