Skip to content

Commit

Permalink
[OTE-245] Update OI after fill and added unit tests (#1231)
Browse files Browse the repository at this point in the history
* Update OI after fill and added unit tests

* nits

* fix unit test
  • Loading branch information
teddyding committed Mar 25, 2024
1 parent b2d63af commit 82c2dec
Show file tree
Hide file tree
Showing 13 changed files with 555 additions and 41 deletions.
23 changes: 19 additions & 4 deletions protocol/testutil/constants/perpetuals.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,12 @@ var LiquidityTiers = []perptypes.LiquidityTier{
// Perpetual OI setup in tests
var (
BtcUsd_OpenInterest1_AtomicRes8 = perptypes.OpenInterestDelta{
PerpetualId: 0,
BaseQuantumsDelta: big.NewInt(100_000_000),
PerpetualId: 0,
BaseQuantums: big.NewInt(100_000_000),
}
EthUsd_OpenInterest1_AtomicRes9 = perptypes.OpenInterestDelta{
PerpetualId: 1,
BaseQuantumsDelta: big.NewInt(1_000_000_000),
PerpetualId: 1,
BaseQuantums: big.NewInt(1_000_000_000),
}
DefaultTestPerpOIs = []perptypes.OpenInterestDelta{
BtcUsd_OpenInterest1_AtomicRes8,
Expand Down Expand Up @@ -277,6 +277,19 @@ var (
FundingIndex: dtypes.ZeroInt(),
OpenInterest: dtypes.NewInt(100_000_000),
}
BtcUsd_20PercentInitial_10PercentMaintenance_OpenInterest2 = perptypes.Perpetual{
Params: perptypes.PerpetualParams{
Id: 0,
Ticker: "BTC-USD 20/10 margin requirements",
MarketId: uint32(0),
AtomicResolution: int32(-8),
DefaultFundingPpm: int32(0),
LiquidityTier: uint32(3),
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_CROSS,
},
FundingIndex: dtypes.ZeroInt(),
OpenInterest: dtypes.NewInt(200_000_000),
}
BtcUsd_20PercentInitial_10PercentMaintenance_25mmLowerCap_50mmUpperCap = perptypes.Perpetual{
Params: perptypes.PerpetualParams{
Id: 0,
Expand Down Expand Up @@ -379,6 +392,7 @@ var (
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED,
},
FundingIndex: dtypes.ZeroInt(),
OpenInterest: dtypes.ZeroInt(),
}
Iso2Usd_IsolatedMarket = perptypes.Perpetual{
Params: perptypes.PerpetualParams{
Expand All @@ -391,6 +405,7 @@ var (
MarketType: perptypes.PerpetualMarketType_PERPETUAL_MARKET_TYPE_ISOLATED,
},
FundingIndex: dtypes.ZeroInt(),
OpenInterest: dtypes.ZeroInt(),
}
)

Expand Down
2 changes: 1 addition & 1 deletion protocol/testutil/perpetuals/perpetuals.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func SetUpDefaultPerpOIsForTest(
k.ModifyOpenInterest(
ctx,
perp.Params.Id,
perpOI.BaseQuantumsDelta,
perpOI.BaseQuantums,
),
)
}
Expand Down
22 changes: 22 additions & 0 deletions protocol/x/clob/keeper/deleveraging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,9 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
expectedSubaccounts []satypes.Subaccount
expectedFills []types.MatchPerpetualDeleveraging_Fill
expectedQuantumsRemaining *big.Int
// Expected remaining OI after test.
// The test initializes each perp with default open interest of 1 full coin.
expectedOpenInterest *big.Int
}{
"Can get one offsetting subaccount for deleveraged short": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -496,6 +499,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: new(big.Int),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
"Can get one offsetting subaccount for deleveraged long": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -523,6 +527,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: new(big.Int),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
"Can get multiple offsetting subaccounts": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -587,6 +592,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: new(big.Int),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
"Skips subaccounts with positions on the same side": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -618,6 +624,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: new(big.Int),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
"Skips subaccounts with no open position for the given perpetual": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -649,6 +656,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: new(big.Int),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
"Skips subaccounts with non-overlapping bankruptcy prices": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -680,6 +688,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: new(big.Int),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
"Returns an error if not enough subaccounts to fully deleverage liquidated subaccount's position": {
subaccounts: []satypes.Subaccount{
Expand All @@ -692,6 +701,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
expectedSubaccounts: nil,
expectedFills: []types.MatchPerpetualDeleveraging_Fill{},
expectedQuantumsRemaining: big.NewInt(100_000_000),
expectedOpenInterest: big.NewInt(100_000_000),
},
"Can offset subaccount with multiple positions, first position is offset leaving TNC constant": {
subaccounts: []satypes.Subaccount{
Expand Down Expand Up @@ -731,6 +741,7 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
},
},
expectedQuantumsRemaining: big.NewInt(0),
expectedOpenInterest: new(big.Int), // fully deleveraged
},
}

Expand Down Expand Up @@ -865,6 +876,17 @@ func TestOffsetSubaccountPerpetualPosition(t *testing.T) {
for _, subaccount := range tc.expectedSubaccounts {
require.Equal(t, subaccount, ks.SubaccountsKeeper.GetSubaccount(ks.Ctx, *subaccount.Id))
}

if tc.expectedOpenInterest != nil {
gotPerp, err := ks.PerpetualsKeeper.GetPerpetual(ks.Ctx, tc.perpetualId)
require.NoError(t, err)
require.Zero(t,
tc.expectedOpenInterest.Cmp(gotPerp.OpenInterest.BigInt()),
"expected open interest %s, got %s",
tc.expectedOpenInterest.String(),
gotPerp.OpenInterest.String(),
)
}
})
}
}
Expand Down
31 changes: 31 additions & 0 deletions protocol/x/clob/keeper/liquidations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ func TestPlacePerpetualLiquidation(t *testing.T) {
// Expectations.
expectedPlacedOrders []*types.MsgPlaceOrder
expectedMatchedOrders []*types.ClobMatch
// Expected remaining OI after test.
// The test initializes each perp with default open interest of 1 full coin.
expectedOpenInterests map[uint32]*big.Int
}{
`Can place a liquidation that doesn't match any maker orders`: {
perpetuals: []perptypes.Perpetual{
Expand All @@ -67,6 +70,9 @@ func TestPlacePerpetualLiquidation(t *testing.T) {

expectedPlacedOrders: []*types.MsgPlaceOrder{},
expectedMatchedOrders: []*types.ClobMatch{},
expectedOpenInterests: map[uint32]*big.Int{
constants.BtcUsd_SmallMarginRequirement.Params.Id: big.NewInt(100_000_000), // unchanged
},
},
`Can place a liquidation that matches maker orders`: {
perpetuals: []perptypes.Perpetual{
Expand Down Expand Up @@ -107,6 +113,9 @@ func TestPlacePerpetualLiquidation(t *testing.T) {
},
),
},
expectedOpenInterests: map[uint32]*big.Int{
constants.BtcUsd_SmallMarginRequirement.Params.Id: new(big.Int), // fully liquidated
},
},
`Can place a liquidation that matches maker orders and removes undercollateralized ones`: {
perpetuals: []perptypes.Perpetual{
Expand Down Expand Up @@ -149,6 +158,9 @@ func TestPlacePerpetualLiquidation(t *testing.T) {
},
),
},
expectedOpenInterests: map[uint32]*big.Int{
constants.BtcUsd_SmallMarginRequirement.Params.Id: new(big.Int), // fully liquidated
},
},
`Can place a liquidation that matches maker orders with maker rebates and empty fee collector`: {
perpetuals: []perptypes.Perpetual{
Expand Down Expand Up @@ -189,6 +201,9 @@ func TestPlacePerpetualLiquidation(t *testing.T) {
},
),
},
expectedOpenInterests: map[uint32]*big.Int{
constants.BtcUsd_SmallMarginRequirement.Params.Id: new(big.Int), // fully liquidated
},
},
`Can place a liquidation that matches maker orders with maker rebates`: {
perpetuals: []perptypes.Perpetual{
Expand Down Expand Up @@ -228,6 +243,9 @@ func TestPlacePerpetualLiquidation(t *testing.T) {
},
),
},
expectedOpenInterests: map[uint32]*big.Int{
constants.BtcUsd_SmallMarginRequirement.Params.Id: new(big.Int), // fully liquidated
},
},
}
for name, tc := range tests {
Expand Down Expand Up @@ -342,6 +360,19 @@ func TestPlacePerpetualLiquidation(t *testing.T) {
_, _, err = ks.ClobKeeper.PlacePerpetualLiquidation(ctx, tc.order)
require.NoError(t, err)

for _, perp := range tc.perpetuals {
if expectedOI, exists := tc.expectedOpenInterests[perp.Params.Id]; exists {
gotPerp, err := ks.PerpetualsKeeper.GetPerpetual(ks.Ctx, perp.Params.Id)
require.NoError(t, err)
require.Zero(t,
expectedOI.Cmp(gotPerp.OpenInterest.BigInt()),
"expected open interest %s, got %s",
expectedOI.String(),
gotPerp.OpenInterest.String(),
)
}
}

// Verify test expectations.
// TODO(DEC-1979): Refactor these tests to support the operations queue refactor.
// placedOrders, matchedOrders := memClob.GetPendingFills(ctx)
Expand Down
Loading

0 comments on commit 82c2dec

Please sign in to comment.