Skip to content

Commit

Permalink
test: add checks for funding payments and loss socialisation to integ…
Browse files Browse the repository at this point in the history
…ration tests

Signed-off-by: Elias Van Ootegem <[email protected]>
  • Loading branch information
EVODelavega committed Sep 3, 2024
1 parent 78c4213 commit 2085c56
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 7 deletions.
4 changes: 4 additions & 0 deletions core/events/loss_socialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func NewLossSocializationEvent(ctx context.Context, partyID, marketID string, am
}
}

func (l LossSoc) LossType() types.LossType {
return l.lType
}

func (l LossSoc) IsFunding() bool {
return l.lType == types.LossTypeFunding
}
Expand Down
8 changes: 8 additions & 0 deletions core/integration/features/perpetual.feature
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ Feature: Simple test creating a perpetual market.
| start | end | internal twap | external twap | funding payment | funding rate |
| 1575072007 | 1575072014 | 9820000000000000 | 9750000000000000 | 70000000000000 | 0.0071794871794872 |
| 1575072014 | | 9890000000000000 | 9720000000000000 | | |
And the following funding payment events should be emitted:
| party | market | amount |
| trader2 | ETH/DEC19 | -100000000 |
| trader2 | ETH/DEC19 | 700000000 |
| trader1 | ETH/DEC19 | 100000000 |
| trader1 | ETH/DEC19 | -700000000 |
| trader3 | ETH/DEC19 | -1400000000 |
| trader4 | ETH/DEC19 | 1400000000 |
# payments for trader3 and trader4 should be twice those of trader1 and trader2
And the following transfers should happen:
| type | from | to | from account | to account | market id | amount | asset |
Expand Down
20 changes: 14 additions & 6 deletions core/integration/features/settlement/0053-PERP-039.feature
Original file line number Diff line number Diff line change
Expand Up @@ -108,26 +108,34 @@ Feature: If a market insurance pool does not have enough funds to cover a fundin
And the mark price should be "1200" for the market "ETH/DEC19"

When time is updated to "2021-08-12T11:04:12Z"
Then system unix time is "1628766252"
And system unix time is "1628766252"

When the oracles broadcast data with block time signed with "0xCAFECAFE1":
And the oracles broadcast data with block time signed with "0xCAFECAFE1":
| name | value | time offset |
| perp.funding.cue | 1628766252 | 0s |

And the following funding period events should be emitted:
Then the following funding period events should be emitted:
| start | end | internal twap | external twap | funding payment |
| 1612998252 | 1628766252 | 1200 | 6200 | -5000 |
| 1612998252 | 1628766252 | 1200 | 6200 | -5000 |

# funding payment is 5000000 but party "aux" only has 4793200
# check that loss socialisation has happened and that the insurance pool has been cleared to indicate
# that there wasn't enough in there to cover the funding payment hence the winning parties received a haircut
#And debug funding payment events
And the following funding payment events should be emitted:
| party | market | amount | loss amount | loss type |
| party2 | ETH/DEC19 | 5000000 | -68867 | TYPE_FUNDING_PAYMENT |
| party3 | ETH/DEC19 | 5000000 | -68866 | TYPE_FUNDING_PAYMENT |
| aux2 | ETH/DEC19 | 5000000 | -68867 | TYPE_FUNDING_PAYMENT |
| aux | ETH/DEC19 | -5000000 | 206600 | TYPE_FUNDING_PAYMENT |
| party1 | ETH/DEC19 | -10000000 | | |
And the following transfers should happen:
| from | to | from account | to account | market id | amount | asset | type |
| party1 | market | ACCOUNT_TYPE_MARGIN | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 1008000 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| party1 | market | ACCOUNT_TYPE_GENERAL | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 8992000 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| aux | market | ACCOUNT_TYPE_MARGIN | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 648000 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| aux | market | ACCOUNT_TYPE_MARGIN | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 648000 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| aux | market | ACCOUNT_TYPE_GENERAL | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 4145200 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| market | market | ACCOUNT_TYPE_INSURANCE | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 200 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| market | market | ACCOUNT_TYPE_INSURANCE | ACCOUNT_TYPE_SETTLEMENT | ETH/DEC19 | 200 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_LOSS |
| market | aux2 | ACCOUNT_TYPE_SETTLEMENT | ACCOUNT_TYPE_MARGIN | ETH/DEC19 | 4931133 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_WIN |
| market | party2 | ACCOUNT_TYPE_SETTLEMENT | ACCOUNT_TYPE_MARGIN | ETH/DEC19 | 4931133 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_WIN |
| market | party3 | ACCOUNT_TYPE_SETTLEMENT | ACCOUNT_TYPE_MARGIN | ETH/DEC19 | 4931134 | USD | TRANSFER_TYPE_PERPETUALS_FUNDING_WIN |
Expand Down
7 changes: 7 additions & 0 deletions core/integration/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,10 @@ func InitializeScenario(s *godog.ScenarioContext) {
s.Step(`^debug network parameter "([^"]*)"$`, func(name string) error {
return steps.DebugNetworkParameter(execsetup.log, execsetup.netParams, name)
})
s.Step(`^debug funding payment events$`, func() error {
steps.DebugFundingPaymentsEvents(execsetup.broker, execsetup.log)
return nil
})

// Event steps
s.Step(`^clear all events$`, func() error {
Expand All @@ -712,6 +716,9 @@ func InitializeScenario(s *godog.ScenarioContext) {
s.Step(`^the following funding period events should be emitted:$`, func(table *godog.Table) error {
return steps.TheFollowingFundingPeriodEventsShouldBeEmitted(execsetup.broker, table)
})
s.Step(`^the following funding payment events should be emitted:$`, func(table *godog.Table) error {
return steps.TheFollowingFundingPaymentEventsShouldBeEmitted(execsetup.broker, table)
})
s.Step(`^the following events should be emitted:$`, func(table *godog.Table) error {
return steps.TheFollowingEventsShouldBeEmitted(execsetup.broker, table)
})
Expand Down
227 changes: 227 additions & 0 deletions core/integration/steps/funding_payment_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import (

"code.vegaprotocol.io/vega/core/events"
"code.vegaprotocol.io/vega/core/integration/stubs"
"code.vegaprotocol.io/vega/core/types"
"code.vegaprotocol.io/vega/libs/num"
"code.vegaprotocol.io/vega/logging"
eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"

"github.com/cucumber/godog"
)
Expand Down Expand Up @@ -49,6 +52,171 @@ func TheFollowingFundingPeriodEventsShouldBeEmitted(broker *stubs.BrokerStub, ta
return nil
}

func TheFollowingFundingPaymentEventsShouldBeEmitted(broker *stubs.BrokerStub, table *godog.Table) error {
paymentEvts := broker.GetFundginPaymentEvents()
checkLoss := false
rows := parseFundingPaymentsTable(table)
matchers := make([]FundingPaymentsWrapper, 0, len(rows))
for _, row := range rows {
w := FundingPaymentsWrapper{
r: row,
}
matchers = append(matchers, w)
checkLoss = (checkLoss || w.CheckLoss())
}
// map the events by party and market
lsEvt := map[string]map[string][]*events.LossSoc{}
if checkLoss {
for _, ls := range broker.GetLossSoc() {
mID, pID := ls.MarketID(), ls.PartyID()
mmap, ok := lsEvt[mID]
if !ok {
mmap = map[string][]*events.LossSoc{}
}
ps, ok := mmap[pID]
if !ok {
ps = []*events.LossSoc{}
}
ps = append(ps, ls)
mmap[pID] = ps
lsEvt[mID] = mmap
}
}
// get by party and market
pEvts := map[string]map[string][]*eventspb.FundingPayment{}
for _, pe := range paymentEvts {
mID := pe.MarketID()
mmap, ok := pEvts[mID]
if !ok {
mmap = map[string][]*eventspb.FundingPayment{}
}
for _, fp := range pe.FundingPayments().Payments {
fps, ok := mmap[fp.PartyId]
if !ok {
fps = []*eventspb.FundingPayment{}
}
fps = append(fps, fp)
mmap[fp.PartyId] = fps
}
pEvts[mID] = mmap
}
// now start matching
for _, row := range matchers {
mID, pID := row.Market(), row.Party()
mmap, ok := pEvts[mID]
if !ok {
return fmt.Errorf("could not find funding payment events for market %s", mID)
}
ppayments, ok := mmap[pID]
if !ok {
return fmt.Errorf("could not find funding payment events for party %s in market %s", pID, mID)
}
matched := false
amt := row.Amount().String()
for _, fp := range ppayments {
if fp.Amount == amt {
matched = true
break
}
}
if !matched {
return fmt.Errorf("could not find funding payment of amount %s for party %s in market %s", amt, pID, mID)
}
if !checkLoss || !row.CheckLoss() {
continue
}
mloss, ok := lsEvt[mID]
if !ok {
return fmt.Errorf("could not find loss socialisation events for market %s", mID)
}
pLoss, ok := mloss[pID]
if !ok {
return fmt.Errorf("could not find loss socialisation event for party %s in market %s", pID, mID)
}
matched = false
for _, le := range pLoss {
if !row.matchLossType(le.LossType()) {
continue
}
if !row.matchLossAmount(le.Amount()) {
continue
}
matched = true
break
}
if !matched {
return fmt.Errorf("could not find loss amount/type %s/%s for party %s in market %s", row.LossAmount().String(), row.LossType().String(), pID, mID)
}
}
return nil
}

func DebugFundingPaymentsEvents(broker *stubs.BrokerStub, log *logging.Logger) {
paymentEvts := broker.GetFundginPaymentEvents()
lossSoc := broker.GetLossSoc()
pEvts := map[string]map[string][]*eventspb.FundingPayment{}
lsEvt := map[string]map[string][]*events.LossSoc{}
for _, pe := range paymentEvts {
mID := pe.MarketID()
mmap, ok := pEvts[mID]
if !ok {
mmap = map[string][]*eventspb.FundingPayment{}
}
for _, fp := range pe.FundingPayments().Payments {
fps, ok := mmap[fp.PartyId]
if !ok {
fps = []*eventspb.FundingPayment{}
}
fps = append(fps, fp)
mmap[fp.PartyId] = fps
}
pEvts[mID] = mmap
}
for _, le := range lossSoc {
mID, pID := le.MarketID(), le.PartyID()
// ignore loss socialisation unless they are related to funding payments:
if mmap, ok := pEvts[mID]; !ok {
continue
} else if _, ok := mmap[pID]; !ok {
// also skip the parties that don't have funding payment events.
continue
}
mmap, ok := lsEvt[mID]
if !ok {
mmap = map[string][]*events.LossSoc{}
}
// ignore irrelevant parties?
ps, ok := mmap[pID]
if !ok {
ps = []*events.LossSoc{}
}
ps = append(ps, le)
mmap[pID] = ps
lsEvt[mID] = mmap
}
log.Info("DUMPING FUNDING PAYMENTS EVENTS")
for mID, fpMap := range pEvts {
log.Infof("Market ID: %s\n", mID)
for pID, fpe := range fpMap {
log.Infof("PartyID: %s\n", pID)
var lSoc []*events.LossSoc
lossM, ok := lsEvt[mID]
if ok {
lSoc = lossM[pID]
}
for i, fe := range fpe {
log.Infof("%d: Amount %s\n", i+1, fe.Amount)
}
if len(lSoc) > 0 {
log.Info("\nLOSS SOCIALISATION:\n")
}
for i, le := range lSoc {
log.Infof("%d: Amount: %s - Type: %s\n", i+1, le.Amount().String(), le.LossType().String())
}
}
}
}

func DebugFundingPeriodEventss(broker *stubs.BrokerStub, log *logging.Logger) {
log.Info("DUMPING FUNDING PERIOD EVENTS")
data := broker.GetFundingPeriodEvents()
Expand Down Expand Up @@ -112,6 +280,10 @@ type FundingPeriodEventWrapper struct {
row RowWrapper
}

type FundingPaymentsWrapper struct {
r RowWrapper
}

func parseFundingPeriodEventTable(table *godog.Table) []RowWrapper {
return StrictParseTable(table, []string{
"internal twap",
Expand All @@ -124,6 +296,61 @@ func parseFundingPeriodEventTable(table *godog.Table) []RowWrapper {
})
}

func parseFundingPaymentsTable(table *godog.Table) []RowWrapper {
return StrictParseTable(table, []string{
"party",
"market",
"amount",
}, []string{
"loss type",
"loss amount",
})
}

func (f FundingPaymentsWrapper) Party() string {
return f.r.MustStr("party")
}

func (f FundingPaymentsWrapper) Market() string {
return f.r.MustStr("market")
}

func (f FundingPaymentsWrapper) Amount() *num.Int {
return f.r.MustInt("amount")
}

func (f FundingPaymentsWrapper) LossAmount() *num.Int {
if !f.r.HasColumn("loss amount") {
return num.IntZero()
}
return f.r.MustInt("loss amount")
}

func (f FundingPaymentsWrapper) LossType() types.LossType {
if !f.r.HasColumn("loss type") {
return types.LossTypeUnspecified
}
return f.r.MustLossType("loss type")
}

func (f FundingPaymentsWrapper) CheckLoss() bool {
return f.r.HasColumn("loss type") || f.r.HasColumn("loss amount")
}

func (f FundingPaymentsWrapper) matchLossType(t types.LossType) bool {
if !f.r.HasColumn("loss type") {
return true
}
return f.LossType() == t
}

func (f FundingPaymentsWrapper) matchLossAmount(amt *num.Int) bool {
if !f.r.HasColumn("loss amount") {
return true
}
return f.LossAmount().EQ(amt)
}

func (f FundingPeriodEventWrapper) InternalTWAP() string {
return f.row.MustStr("internal twap")
}
Expand Down
22 changes: 22 additions & 0 deletions core/integration/steps/table_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,34 @@ func EventType(rawValue string) (events.Type, error) {
return *ty, nil
}

func (r RowWrapper) LossType(name string) types.LossType {
lt, err := LossType(r.Str(name))
if err != nil {
return types.LossTypeUnspecified
}
return lt
}

func (r RowWrapper) MustLossType(name string) types.LossType {
lt, err := LossType(r.MustStr(name))
panicW(name, err)
return lt
}

func (r RowWrapper) MustOrderType(name string) types.OrderType {
orderType, err := OrderType(r.MustStr(name))
panicW(name, err)
return orderType
}

func LossType(rawValue string) (types.LossType, error) {
lt, ok := eventspb.LossSocialization_Type_value[rawValue]
if !ok {
return types.LossType(lt), fmt.Errorf("invalid loss socialisation type: %v", rawValue)
}
return types.LossType(lt), nil
}

func OrderType(rawValue string) (types.OrderType, error) {
ty, ok := proto.Order_Type_value[rawValue]
if !ok {
Expand Down
Loading

0 comments on commit 2085c56

Please sign in to comment.