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

[TRA-64] Use market specific insurance fund for cross or isolated markets #1132

Merged
merged 8 commits into from
Mar 5, 2024
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
2 changes: 1 addition & 1 deletion protocol/app/module_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var (
bridgemoduletypes.ModuleName: {authtypes.Minter},
// subaccounts module account holds tokens for all subaccounts.
satypes.ModuleName: nil,
// clob insurance fund account manages insurance fund for liquidations.
// insurance fund account manages insurance fund for liquidations.
perpetualsmoduletypes.InsuranceFundName: nil,
// rewards treasury account distribute funds trading accounts.
rewardsmoduletypes.TreasuryAccountName: nil,
Expand Down
4 changes: 3 additions & 1 deletion protocol/daemons/liquidation/client/grpc_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package client_test

import (
"context"
"cosmossdk.io/log"
"errors"
"testing"

"cosmossdk.io/log"

"github.com/cosmos/cosmos-sdk/types/query"
"github.com/dydxprotocol/v4-chain/protocol/daemons/flags"
"github.com/dydxprotocol/v4-chain/protocol/daemons/liquidation/api"
Expand Down Expand Up @@ -409,6 +410,7 @@ func TestGetAllMarketPrices(t *testing.T) {
response2 := &pricestypes.QueryAllMarketPricesResponse{
MarketPrices: []pricestypes.MarketPrice{
constants.TestMarketPrices[2],
constants.TestMarketPrices[3],
},
}
mck.On("AllMarketPrices", mock.Anything, req2).Return(response2, nil)
Expand Down
2 changes: 1 addition & 1 deletion protocol/mocks/ClobKeeper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion protocol/testing/e2e/gov/perpetuals_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

var (
TEST_PERPETUAL_PARAMS = perptypes.PerpetualParams{
Id: 765,
Id: 0,
Ticker: "BTC-ADV4TNT",
MarketId: 123,
AtomicResolution: -8,
Expand Down
52 changes: 52 additions & 0 deletions protocol/testutil/constants/perpetuals.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,60 @@ var (
},
FundingIndex: dtypes.ZeroInt(),
}
IsoUsd_IsolatedMarket = perptypes.Perpetual{
Params: perptypes.PerpetualParams{
Id: 3,
Ticker: "ISO-USD",
MarketId: uint32(3),
AtomicResolution: int32(-9),
DefaultFundingPpm: int32(0),
LiquidityTier: uint32(3),
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED,
},
FundingIndex: dtypes.ZeroInt(),
}
)

var TestMarketPerpetuals = []perptypes.Perpetual{
{
Params: perptypes.PerpetualParams{
Id: 0,
Ticker: "BTC-USD",
MarketId: uint32(0),
AtomicResolution: int32(-10),
DefaultFundingPpm: int32(0),
LiquidityTier: uint32(0),
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
},
FundingIndex: dtypes.ZeroInt(),
},
{
Params: perptypes.PerpetualParams{
Id: 1,
Ticker: "ETH-USD",
MarketId: uint32(1),
AtomicResolution: int32(-9),
DefaultFundingPpm: int32(0),
LiquidityTier: uint32(0),
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
},
FundingIndex: dtypes.ZeroInt(),
},
{
Params: perptypes.PerpetualParams{
Id: 2,
Ticker: "SOL-USD",
MarketId: uint32(2),
AtomicResolution: int32(-9),
DefaultFundingPpm: int32(0),
LiquidityTier: uint32(3),
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
},
FundingIndex: dtypes.ZeroInt(),
},
IsoUsd_IsolatedMarket,
}

// AddPremiumVotes messages.
var (
TestAddPremiumVotesMsg = &perptypes.MsgAddPremiumVotes{
Expand Down
10 changes: 10 additions & 0 deletions protocol/testutil/constants/pricefeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var (
MarketId0 = uint32(0)
MarketId1 = uint32(1)
MarketId2 = uint32(2)
MarketId3 = uint32(3)

MarketId7 = uint32(7)
MarketId8 = uint32(8)
Expand Down Expand Up @@ -269,23 +270,32 @@ var (
Exchange2_Price2_TimeT,
},
},
{
MarketId: MarketId3,
ExchangePrices: []*api.ExchangePrice{
Exchange3_Price3_TimeT,
},
},
}
AtTimeTSingleExchangeSmoothedPrices = map[uint32]uint64{
MarketId0: Exchange0_Price4_TimeT.Price,
MarketId1: Exchange1_Price1_TimeT.Price,
MarketId2: Exchange2_Price2_TimeT.Price,
MarketId3: Exchange3_Price3_TimeT.Price,
}

AtTimeTSingleExchangeSmoothedPricesPlus10 = map[uint32]uint64{
MarketId0: Exchange0_Price4_TimeT.Price + 10,
MarketId1: Exchange1_Price1_TimeT.Price + 10,
MarketId2: Exchange2_Price2_TimeT.Price + 10,
MarketId3: Exchange3_Price3_TimeT.Price + 10,
}

AtTimeTSingleExchangeSmoothedPricesPlus7 = map[uint32]uint64{
MarketId0: Exchange0_Price4_TimeT.Price + 7,
MarketId1: Exchange1_Price1_TimeT.Price + 7,
MarketId2: Exchange2_Price2_TimeT.Price + 7,
MarketId3: Exchange3_Price3_TimeT.Price + 7,
}

MixedTimePriceUpdate = []*api.MarketPriceUpdate{
Expand Down
26 changes: 26 additions & 0 deletions protocol/testutil/constants/prices.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
MaticUsdPair = "MATIC-USD"
SolUsdPair = "SOL-USD"
LtcUsdPair = "LTC-USD"
IsoUsdPair = "ISO-USD"

BtcUsdExponent = -5
EthUsdExponent = -6
Expand All @@ -34,6 +35,7 @@ const (
CrvUsdExponent = -10
SolUsdExponent = -8
LtcUsdExponent = -7
IsoUsdExponent = -8

CoinbaseExchangeName = "Coinbase"
BinanceExchangeName = "Binance"
Expand Down Expand Up @@ -201,6 +203,15 @@ var TestMarketExchangeConfigs = map[pricefeedclient.MarketId]string{
}
]
}`,
exchange_config.MARKET_ISO_USD: `{
"exchanges": [
{
"exchangeName": "Binance",
"ticker": "ISOUSDT",
"adjustByMarket": "USDT-USD"
}
]
}`,
}

var TestMarketParams = []types.MarketParam{
Expand Down Expand Up @@ -228,6 +239,14 @@ var TestMarketParams = []types.MarketParam{
MinPriceChangePpm: 50,
ExchangeConfigJson: TestMarketExchangeConfigs[exchange_config.MARKET_SOL_USD],
},
{
Id: 3,
Pair: IsoUsdPair,
Exponent: IsoUsdExponent,
MinExchanges: 1,
MinPriceChangePpm: 50,
ExchangeConfigJson: TestMarketExchangeConfigs[exchange_config.MARKET_ISO_USD],
},
}

var TestMarketPrices = []types.MarketPrice{
Expand All @@ -246,12 +265,18 @@ var TestMarketPrices = []types.MarketPrice{
Exponent: SolUsdExponent,
Price: FiveBillion, // 50$ == 1 SOL
},
{
Id: 3,
Exponent: IsoUsdExponent,
Price: FiveBillion, // 50$ == 1 ISO
},
}

var TestMarketIdsToExponents = map[uint32]int32{
0: BtcUsdExponent,
1: EthUsdExponent,
2: SolUsdExponent,
3: IsoUsdExponent,
}

var TestPricesGenesisState = types.GenesisState{
Expand All @@ -264,6 +289,7 @@ var (
types.NewMarketPriceUpdate(MarketId0, Price5),
types.NewMarketPriceUpdate(MarketId1, Price6),
types.NewMarketPriceUpdate(MarketId2, Price7),
types.NewMarketPriceUpdate(MarketId3, Price4),
}

// `MsgUpdateMarketPrices`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ const (
// MARKET_TEST_USD is the id used for the TEST-USD market pair.
MARKET_TEST_USD types.MarketId = 33

// Arbitrary isolated market
MARKET_ISO_USD types.MarketId = 999_999

// Non-trading markets.
// MARKET_USDT_USD is the id for the USDT-USD market pair.
MARKET_USDT_USD types.MarketId = 1_000_000
Expand Down
16 changes: 16 additions & 0 deletions protocol/testutil/keeper/perpetuals.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,22 @@ func PopulateTestPremiumStore(
}
}

func CreateTestPerpetuals(t *testing.T, ctx sdk.Context, k *keeper.Keeper) {
for _, p := range constants.TestMarketPerpetuals {
_, err := k.CreatePerpetual(
ctx,
p.Params.Id,
p.Params.Ticker,
p.Params.MarketId,
p.Params.AtomicResolution,
p.Params.DefaultFundingPpm,
p.Params.LiquidityTier,
p.Params.MarketType,
)
require.NoError(t, err)
}
}

func CreateTestLiquidityTiers(t *testing.T, ctx sdk.Context, k *keeper.Keeper) {
for _, l := range constants.LiquidityTiers {
_, err := k.SetLiquidityTier(
Expand Down
2 changes: 1 addition & 1 deletion protocol/x/clob/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func EndBlocker(
// Emit relevant metrics at the end of every block.
metrics.SetGauge(
metrics.InsuranceFundBalance,
metrics.GetMetricValueFromBigInt(keeper.GetInsuranceFundBalance(ctx)),
metrics.GetMetricValueFromBigInt(keeper.GetCrossInsuranceFundBalance(ctx)),
)
}

Expand Down
39 changes: 26 additions & 13 deletions protocol/x/clob/keeper/deleveraging.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"math/big"
"time"

types2 "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"
perptypes "github.com/dydxprotocol/v4-chain/protocol/x/perpetuals/types"

errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/telemetry"
Expand Down Expand Up @@ -130,20 +130,36 @@ func (k Keeper) MaybeDeleverageSubaccount(
return quantumsDeleveraged, err
}

// GetInsuranceFundBalance returns the current balance of the insurance fund (in quote quantums).
// GetInsuranceFundBalance returns the current balance of the specific insurance fund based on the
// perpetual (in quote quantums).
// This calls the Bank Keeper’s GetBalance() function for the Module Address of the insurance fund.
func (k Keeper) GetInsuranceFundBalance(
ctx sdk.Context,
) (
balance *big.Int,
) {
func (k Keeper) GetInsuranceFundBalance(ctx sdk.Context, perpetualId uint32) (balance *big.Int) {
shrenujb marked this conversation as resolved.
Show resolved Hide resolved
usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id)
if !exists {
panic("GetInsuranceFundBalance: Usdc asset not found in state")
}
insuranceFundAddr, err := k.perpetualsKeeper.GetInsuranceFundModuleAddress(ctx, perpetualId)
if err != nil {
return nil
}
insuranceFundBalance := k.bankKeeper.GetBalance(
ctx,
types2.InsuranceFundModuleAddress,
insuranceFundAddr,
usdcAsset.Denom,
)

// Return as big.Int.
return insuranceFundBalance.Amount.BigInt()
}
Comment on lines +133 to +153
Copy link
Contributor

Choose a reason for hiding this comment

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

The implementation of GetInsuranceFundBalance now includes a perpetualId parameter, allowing it to fetch the balance for a specific perpetual's insurance fund. This is a crucial update for supporting market-specific insurance funds. However, there are a few points to consider:

  • The function now panics if the USDC asset is not found. Ensure that this behavior is consistent with the overall error handling strategy of the application. It might be more appropriate to return an error instead of panicking to allow the caller to handle the situation gracefully.
  • The error handling for GetInsuranceFundModuleAddress is to return nil if an error occurs. This could lead to silent failures. Consider logging the error or handling it in a way that makes the failure more visible or actionable.


func (k Keeper) GetCrossInsuranceFundBalance(ctx sdk.Context) (balance *big.Int) {
usdcAsset, exists := k.assetsKeeper.GetAsset(ctx, assettypes.AssetUsdc.Id)
if !exists {
panic("GetCrossInsuranceFundBalance: Usdc asset not found in state")
}
insuranceFundBalance := k.bankKeeper.GetBalance(
ctx,
perptypes.InsuranceFundModuleAddress,
usdcAsset.Denom,
)

Expand Down Expand Up @@ -261,18 +277,15 @@ func (k Keeper) GateWithdrawalsIfNegativeTncSubaccountSeen(
// fund delta. Specifically, this function returns true if either of the following are true:
// - The `insuranceFundDelta` is non-negative.
// - The insurance fund balance + `insuranceFundDelta` is greater-than-or-equal-to 0.
func (k Keeper) IsValidInsuranceFundDelta(
ctx sdk.Context,
insuranceFundDelta *big.Int,
) bool {
func (k Keeper) IsValidInsuranceFundDelta(ctx sdk.Context, insuranceFundDelta *big.Int, perpetualId uint32) bool {
// Non-negative insurance fund deltas are valid.
if insuranceFundDelta.Sign() >= 0 {
return true
}

// The insurance fund delta is valid if the insurance fund balance is non-negative after adding
// the delta.
currentInsuranceFundBalance := k.GetInsuranceFundBalance(ctx)
currentInsuranceFundBalance := k.GetInsuranceFundBalance(ctx, perpetualId)
return new(big.Int).Add(currentInsuranceFundBalance, insuranceFundDelta).Sign() >= 0
}

Expand Down
Loading
Loading