Skip to content

Commit

Permalink
Merge pull request #10096 from vegaprotocol/isolated-margin
Browse files Browse the repository at this point in the history
feat: add isolated margin support
  • Loading branch information
ze97286 authored Dec 18, 2023
2 parents 04d1749 + 962c639 commit a868f06
Show file tree
Hide file tree
Showing 79 changed files with 11,551 additions and 3,688 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [9516](https://github.com/vegaprotocol/vega/issues/9516) - Add filter by transfer ID for ledger entries API.
- [9943](https://github.com/vegaprotocol/vega/issues/9943) - Support amending the order size by defining the target size.
- [9231](https://github.com/vegaprotocol/vega/issues/9231) - Add a `JoinTeam API`
- [10095](https://github.com/vegaprotocol/vega/issues/10095) - Add isolated margin support.
- [10222](https://github.com/vegaprotocol/vega/issues/10222) - Supply bootstrap peers after starting the `IPFS` node to increase reliability.
- [10097](https://github.com/vegaprotocol/vega/issues/10097) - Add funding rate modifiers to perpetual product definition.
- [9981](https://github.com/vegaprotocol/vega/issues/9981) - Support filtering on epoch range on transfers.
Expand Down
3 changes: 2 additions & 1 deletion commands/batch_market_instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ func checkBatchMarketInstructions(cmd *commandspb.BatchMarketInstructions) Error
len(cmd.Amendments)+
len(cmd.Submissions)+
len(cmd.StopOrdersSubmission)+
len(cmd.StopOrdersCancellation) == 0 {
len(cmd.StopOrdersCancellation)+
len(cmd.UpdateMarginMode) == 0 {
return errs.FinalAddForProperty("batch_market_instructions", ErrEmptyBatchMarketInstructions)
}

Expand Down
6 changes: 5 additions & 1 deletion commands/update_margin_mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ func checkUpdateMarginMode(cmd *commandspb.UpdateMarginMode) Errors {
return errs.FinalAddForProperty("update_margin_mode", ErrIsRequired)
}

if cmd.Mode == commandspb.UpdateMarginMode_MODE_CROSS_UNSPECIFIED {
if cmd.Mode == commandspb.UpdateMarginMode_MODE_UNSPECIFIED {
errs.AddForProperty("update_margin_mode.margin_mode", ErrIsNotValid)
}

if _, ok := commandspb.UpdateMarginMode_Mode_name[int32(cmd.Mode)]; !ok {
errs.AddForProperty("update_margin_mode.margin_mode", ErrIsNotValid)
}

Expand Down
2 changes: 1 addition & 1 deletion commands/update_margin_mode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestUpdateMarginMode(t *testing.T) {
{
"unspecified mode",
&commandspb.UpdateMarginMode{
Mode: commandspb.UpdateMarginMode_MODE_CROSS_UNSPECIFIED,
Mode: commandspb.UpdateMarginMode_MODE_UNSPECIFIED,
},
"update_margin_mode.margin_mode",
commands.ErrIsNotValid,
Expand Down
2 changes: 1 addition & 1 deletion core/collateral/checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (e *Engine) getCheckpointBalances() []*checkpoint.AssetBalance {
}
balance.AddSum(acc.Balance)

case types.AccountTypeMargin, types.AccountTypeGeneral, types.AccountTypeHolding, types.AccountTypeBond, types.AccountTypeFeesLiquidity,
case types.AccountTypeMargin, types.AccountTypeOrderMargin, types.AccountTypeGeneral, types.AccountTypeHolding, types.AccountTypeBond, types.AccountTypeFeesLiquidity,
types.AccountTypeInsurance, types.AccountTypeGlobalReward, types.AccountTypeLiquidityFeesBonusDistribution, types.AccountTypeLPLiquidityFees,
types.AccountTypeLPFeeReward, types.AccountTypeMakerReceivedFeeReward, types.AccountTypeMakerPaidFeeReward,
types.AccountTypeMarketProposerReward, types.AccountTypeFeesInfrastructure, types.AccountTypePendingTransfers,
Expand Down
225 changes: 188 additions & 37 deletions core/collateral/engine.go

Large diffs are not rendered by default.

48 changes: 25 additions & 23 deletions core/collateral/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ func testTransferLoss(t *testing.T) {
}

eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 2, len(responses))
resp := responses[0]
Expand Down Expand Up @@ -1011,7 +1011,7 @@ func testTransferComplexLoss(t *testing.T) {
}

eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.Equal(t, 2, len(responses))
resp := responses[0]
assert.NoError(t, err)
Expand Down Expand Up @@ -1049,7 +1049,7 @@ func testTransferLossMissingPartyAccounts(t *testing.T) {
Type: types.TransferTypeLoss,
},
}
resp, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
resp, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.Nil(t, resp)
require.Error(t, err)
assert.Contains(t, err.Error(), "account does not exist:")
Expand Down Expand Up @@ -1128,7 +1128,7 @@ func testProcessBoth(t *testing.T) {
assert.Equal(t, int64(2000), acc.Balance)
}
})
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.Equal(t, 4, len(responses))
assert.NoError(t, err)
resp := responses[0]
Expand Down Expand Up @@ -1237,7 +1237,7 @@ func TestLossSocialization(t *testing.T) {
assert.Equal(t, 534, stringToInt(acc.Balance))
}
})
raw, err := eng.FinalSettlement(context.Background(), testMarketID, transfers, num.UintOne())
raw, err := eng.FinalSettlement(context.Background(), testMarketID, transfers, num.UintOne(), func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 4, len(raw))

Expand Down Expand Up @@ -1308,7 +1308,7 @@ func testSettleBalanceNotZero(t *testing.T) {
r := recover()
require.NotNil(t, r)
}()
_, _, _ = eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
_, _, _ = eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
// this should return an error
}

Expand Down Expand Up @@ -1377,7 +1377,7 @@ func testProcessBothProRated(t *testing.T) {

eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
eng.broker.EXPECT().SendBatch(gomock.Any()).Times(2)
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.Equal(t, 4, len(responses))
assert.NoError(t, err)

Expand Down Expand Up @@ -1466,7 +1466,7 @@ func testProcessBothProRatedMTM(t *testing.T) {
eng.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
// quickly get the interface mocked for this test
transfers := getMTMTransfer(pos)
responses, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
responses, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.Equal(t, 4, len(responses))
assert.NoError(t, err, "was error")
assert.NotEmpty(t, raw)
Expand Down Expand Up @@ -1516,7 +1516,7 @@ func testRemoveDistressedBalance(t *testing.T) {
assert.Equal(t, num.UintZero().Add(insBalance, num.NewUint(100)).String(), acc.Balance)
}
})
resp, err := eng.RemoveDistressed(context.Background(), data, testMarketID, testMarketAsset)
resp, err := eng.RemoveDistressed(context.Background(), data, testMarketID, testMarketAsset, func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 1, len(resp.Entries))

Expand Down Expand Up @@ -1552,7 +1552,7 @@ func testRemoveDistressedNoBalance(t *testing.T) {
party: party,
},
}
resp, err := eng.RemoveDistressed(context.Background(), data, testMarketID, testMarketAsset)
resp, err := eng.RemoveDistressed(context.Background(), data, testMarketID, testMarketAsset, func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 0, len(resp.Entries))

Expand Down Expand Up @@ -1644,7 +1644,7 @@ func testPerpFundingSuccess(t *testing.T) {
}
})
transfers := eng.getTestMTMTransfer(pos)
evts, raw, err := eng.PerpsFundingSettlement(context.Background(), testMarketID, transfers, testMarketAsset, nil)
evts, raw, err := eng.PerpsFundingSettlement(context.Background(), testMarketID, transfers, testMarketAsset, nil, func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 4, len(raw))
assert.NotEmpty(t, evts)
Expand Down Expand Up @@ -1741,7 +1741,7 @@ func testPerpFundingSuccessWithRound(t *testing.T) {
}
})
transfers := eng.getTestMTMTransfer(pos)
evts, raw, err := eng.PerpsFundingSettlement(context.Background(), testMarketID, transfers, testMarketAsset, round)
evts, raw, err := eng.PerpsFundingSettlement(context.Background(), testMarketID, transfers, testMarketAsset, round, func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 3, len(raw))
assert.NotEmpty(t, evts)
Expand Down Expand Up @@ -1847,7 +1847,7 @@ func testMTMSuccess(t *testing.T) {
}
})
transfers := eng.getTestMTMTransfer(pos)
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 4, len(raw))
assert.NotEmpty(t, evts)
Expand Down Expand Up @@ -1885,7 +1885,7 @@ func TestInvalidMarketID(t *testing.T) {
transfers := eng.getTestMTMTransfer(pos)

invalidMarketID := testMarketID + "invalid"
evts, raw, err := eng.MarkToMarket(context.Background(), invalidMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), invalidMarketID, transfers, "BTC", func(string) bool { return true })
assert.Error(t, err)
assert.Equal(t, 0, len(raw))
assert.Empty(t, evts)
Expand Down Expand Up @@ -1922,7 +1922,7 @@ func TestEmptyTransfer(t *testing.T) {
}
transfers := eng.getTestMTMTransfer(pos)

evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 0, len(raw))
assert.Empty(t, evts)
Expand Down Expand Up @@ -1957,7 +1957,7 @@ func TestNoMarginAccount(t *testing.T) {
}
transfers := eng.getTestMTMTransfer(pos)

evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.Error(t, err)
assert.Equal(t, 0, len(raw))
assert.Empty(t, evts)
Expand Down Expand Up @@ -1988,7 +1988,7 @@ func TestNoGeneralAccount(t *testing.T) {
}
transfers := eng.getTestMTMTransfer(pos)

evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.Error(t, err)
assert.Equal(t, 0, len(raw))
assert.Empty(t, evts)
Expand All @@ -2010,7 +2010,7 @@ func TestMTMNoTransfers(t *testing.T) {
transfers := eng.getTestMTMTransfer(pos)

// Empty list of transfers
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 0, len(raw))
assert.Empty(t, evts)
Expand All @@ -2021,7 +2021,7 @@ func TestMTMNoTransfers(t *testing.T) {
party: "test-party",
}
transfers = append(transfers, mt)
evts, raw, err = eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err = eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 0, len(raw))
assert.Equal(t, len(evts), 1)
Expand All @@ -2041,7 +2041,7 @@ func TestFinalSettlementNoTransfers(t *testing.T) {

pos := []*types.Transfer{}

responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 0, len(responses))
}
Expand Down Expand Up @@ -2069,7 +2069,7 @@ func TestFinalSettlementNoSystemAccounts(t *testing.T) {
},
}

responses, err := eng.FinalSettlement(context.Background(), "invalidMarketID", pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), "invalidMarketID", pos, num.UintOne(), func(string) bool { return true })
assert.Error(t, err)
assert.Equal(t, 0, len(responses))
}
Expand Down Expand Up @@ -2112,7 +2112,7 @@ func TestFinalSettlementNotEnoughMargin(t *testing.T) {

eng.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne())
responses, err := eng.FinalSettlement(context.Background(), testMarketID, pos, num.UintOne(), func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 2, len(responses))

Expand Down Expand Up @@ -2273,7 +2273,7 @@ func TestMTMLossSocialization(t *testing.T) {
}
})
transfers := eng.getTestMTMTransfer(pos)
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 4, len(raw))
assert.NotEmpty(t, evts)
Expand Down Expand Up @@ -3145,8 +3145,10 @@ func (m riskFake) Asset() string { return m.asset }
func (m riskFake) MarketID() string { return "" }
func (m riskFake) MarginBalance() *num.Uint { return num.UintZero() }
func (m riskFake) GeneralBalance() *num.Uint { return num.UintZero() }
func (m riskFake) GeneralAccountBalance() *num.Uint { return num.UintZero() }
func (m riskFake) BondBalance() *num.Uint { return num.UintZero() }
func (m riskFake) MarginShortFall() *num.Uint { return m.marginShortFall }
func (m riskFake) OrderMarginBalance() *num.Uint { return num.UintZero() }

type transferFees struct {
tfs []*types.Transfer
Expand Down
15 changes: 15 additions & 0 deletions core/collateral/margins.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type marginUpdate struct {
events.MarketPosition
margin *types.Account
orderMargin *types.Account
general *types.Account
lock *types.Account
bond *types.Account
Expand Down Expand Up @@ -51,6 +52,13 @@ func (n marginUpdate) MarginBalance() *num.Uint {
return n.margin.Balance.Clone()
}

func (n marginUpdate) OrderMarginBalance() *num.Uint {
if n.orderMargin == nil {
return num.UintZero()
}
return n.orderMargin.Balance.Clone()
}

// GeneralBalance here we cumulate both the general
// account and bon account so other package do not have
// to worry about how much funds are available in both
Expand All @@ -68,6 +76,13 @@ func (n marginUpdate) GeneralBalance() *num.Uint {
return num.Sum(bond, gen)
}

func (n marginUpdate) GeneralAccountBalance() *num.Uint {
if n.general != nil && n.general.Balance != nil {
return n.general.Balance
}
return num.UintZero()
}

func (n marginUpdate) MarginShortFall() *num.Uint {
return n.marginShortFall.Clone()
}
Expand Down
4 changes: 2 additions & 2 deletions core/collateral/network_mtm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func testMTMWithNetworkNoLossSoc(t *testing.T) {
}
})
transfers := eng.getTestMTMTransfer(pos)
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 3, len(raw))
assert.NotEmpty(t, evts)
Expand Down Expand Up @@ -219,7 +219,7 @@ func testMTMWithNetworkLossSoc(t *testing.T) {
}
})
transfers := eng.getTestMTMTransfer(pos)
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC")
evts, raw, err := eng.MarkToMarket(context.Background(), testMarketID, transfers, "BTC", func(string) bool { return true })
assert.NoError(t, err)
assert.Equal(t, 3, len(raw))
assert.NotEmpty(t, evts)
Expand Down
4 changes: 4 additions & 0 deletions core/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,14 @@ type Margin interface {
MarketPosition
Asset() string
MarginBalance() *num.Uint
OrderMarginBalance() *num.Uint
GeneralBalance() *num.Uint
BondBalance() *num.Uint
MarketID() string
MarginShortFall() *num.Uint
// as opposed to the GeneralBalance() which actually returns the available balance (general+bond)
// this returns the actual balance of the general account
GeneralAccountBalance() *num.Uint
}

// Risk is an event that summarizes everything and an eventual update to margin account.
Expand Down
11 changes: 7 additions & 4 deletions core/execution/common/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ type Collateral interface {
EnableAsset(ctx context.Context, asset types.Asset) error
GetPartyGeneralAccount(party, asset string) (*types.Account, error)
GetPartyBondAccount(market, partyID, asset string) (*types.Account, error)
GetOrCreatePartyOrderMarginAccount(ctx context.Context, partyID, marketID, asset string) (string, error)
BondUpdate(ctx context.Context, market string, transfer *types.Transfer) (*types.LedgerMovement, error)
BondSpotUpdate(ctx context.Context, market string, transfer *types.Transfer) (*types.LedgerMovement, error)
RemoveBondAccount(partyID, marketID, asset string) error
Expand All @@ -149,20 +150,22 @@ type Collateral interface {
RollbackMarginUpdateOnOrder(ctx context.Context, marketID string, assetID string, transfer *types.Transfer) (*types.LedgerMovement, error)
GetOrCreatePartyBondAccount(ctx context.Context, partyID, marketID, asset string) (*types.Account, error)
CreatePartyMarginAccount(ctx context.Context, partyID, marketID, asset string) (string, error)
FinalSettlement(ctx context.Context, marketID string, transfers []*types.Transfer, factor *num.Uint) ([]*types.LedgerMovement, error)
FinalSettlement(ctx context.Context, marketID string, transfers []*types.Transfer, factor *num.Uint, useGeneralAccountForMarginSearch func(string) bool) ([]*types.LedgerMovement, error)
ClearMarket(ctx context.Context, mktID, asset string, parties []string, keepInsurance bool) ([]*types.LedgerMovement, error)
HasGeneralAccount(party, asset string) bool
ClearPartyMarginAccount(ctx context.Context, party, market, asset string) (*types.LedgerMovement, error)
ClearPartyOrderMarginAccount(ctx context.Context, party, market, asset string) (*types.LedgerMovement, error)
CanCoverBond(market, party, asset string, amount *num.Uint) bool
Hash() []byte
TransferFeesContinuousTrading(ctx context.Context, marketID string, assetID string, ft events.FeesTransfer) ([]*types.LedgerMovement, error)
TransferFees(ctx context.Context, marketID string, assetID string, ft events.FeesTransfer) ([]*types.LedgerMovement, error)
TransferSpotFees(ctx context.Context, marketID string, assetID string, ft events.FeesTransfer) ([]*types.LedgerMovement, error)
TransferSpotFeesContinuousTrading(ctx context.Context, marketID string, assetID string, ft events.FeesTransfer) ([]*types.LedgerMovement, error)
MarginUpdate(ctx context.Context, marketID string, updates []events.Risk) ([]*types.LedgerMovement, []events.Margin, []events.Margin, error)
PerpsFundingSettlement(ctx context.Context, marketID string, transfers []events.Transfer, asset string, round *num.Uint) ([]events.Margin, []*types.LedgerMovement, error)
MarkToMarket(ctx context.Context, marketID string, transfers []events.Transfer, asset string) ([]events.Margin, []*types.LedgerMovement, error)
RemoveDistressed(ctx context.Context, parties []events.MarketPosition, marketID, asset string) (*types.LedgerMovement, error)
IsolatedMarginUpdate(updates []events.Risk) []events.Margin
PerpsFundingSettlement(ctx context.Context, marketID string, transfers []events.Transfer, asset string, round *num.Uint, useGeneralAccountForMarginSearch func(string) bool) ([]events.Margin, []*types.LedgerMovement, error)
MarkToMarket(ctx context.Context, marketID string, transfers []events.Transfer, asset string, useGeneralAccountForMarginSearch func(string) bool) ([]events.Margin, []*types.LedgerMovement, error)
RemoveDistressed(ctx context.Context, parties []events.MarketPosition, marketID, asset string, useGeneralAccount func(string) bool) (*types.LedgerMovement, error)
GetMarketLiquidityFeeAccount(market, asset string) (*types.Account, error)
GetAssetQuantum(asset string) (num.Decimal, error)
GetInsurancePoolBalance(marketID, asset string) (*num.Uint, bool)
Expand Down
Loading

0 comments on commit a868f06

Please sign in to comment.