diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f61d88e1b..0be436482e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - [11583](https://github.com/vegaprotocol/vega/issues/11583) - Rough bound on price interval when matching with `AMMs` is now looser and calculated in the `AMM` engine. - [11624](https://github.com/vegaprotocol/vega/issues/11624) - prevent creation of rewards with no payout, but with high computational cost. - [11619](https://github.com/vegaprotocol/vega/issues/11619) - Fix `EstimatePositions` API for capped futures. +- [11645](https://github.com/vegaprotocol/vega/issues/11645) - Support party stats with no markets to retrieve for all markets. ## 0.78.0 diff --git a/datanode/service/market.go b/datanode/service/market.go index a860d46a1e..f788910bb4 100644 --- a/datanode/service/market.go +++ b/datanode/service/market.go @@ -30,6 +30,7 @@ type MarketStore interface { GetByTxHash(ctx context.Context, txHash entities.TxHash) ([]entities.Market, error) GetAllPaged(ctx context.Context, marketID string, pagination entities.CursorPagination, includeSettled bool) ([]entities.Market, entities.PageInfo, error) ListSuccessorMarkets(ctx context.Context, marketID string, fullHistory bool, pagination entities.CursorPagination) ([]entities.SuccessorMarket, entities.PageInfo, error) + GetAllFees(ctx context.Context) ([]entities.Market, error) } type Markets struct { @@ -51,6 +52,10 @@ func (m *Markets) Initialise(ctx context.Context) error { return nil } +func (m *Markets) GetAllFees(ctx context.Context) ([]entities.Market, error) { + return m.store.GetAllFees(ctx) +} + func (m *Markets) Upsert(ctx context.Context, market *entities.Market) error { if err := m.store.Upsert(ctx, market); err != nil { return err diff --git a/datanode/service/mocks/mocks.go b/datanode/service/mocks/mocks.go index 1844b419ea..44440c2507 100644 --- a/datanode/service/mocks/mocks.go +++ b/datanode/service/mocks/mocks.go @@ -126,6 +126,21 @@ func (m *MockMarketStore) EXPECT() *MockMarketStoreMockRecorder { return m.recorder } +// GetAllFees mocks base method. +func (m *MockMarketStore) GetAllFees(arg0 context.Context) ([]entities.Market, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllFees", arg0) + ret0, _ := ret[0].([]entities.Market) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllFees indicates an expected call of GetAllFees. +func (mr *MockMarketStoreMockRecorder) GetAllFees(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllFees", reflect.TypeOf((*MockMarketStore)(nil).GetAllFees), arg0) +} + // GetAllPaged mocks base method. func (m *MockMarketStore) GetAllPaged(arg0 context.Context, arg1 string, arg2 entities.CursorPagination, arg3 bool) ([]entities.Market, entities.PageInfo, error) { m.ctrl.T.Helper() diff --git a/datanode/service/party_stats.go b/datanode/service/party_stats.go index 9dd02a31af..ec6efc80c6 100644 --- a/datanode/service/party_stats.go +++ b/datanode/service/party_stats.go @@ -52,6 +52,8 @@ type VRSStore interface { // MktStore is a duplicate interface at this point, but again: custom method fetching list of markets would be handy. type MktStore interface { GetByIDs(ctx context.Context, marketID []string) ([]entities.Market, error) + // NB: although it returns Market entity, all it has is id and fees. Trying to access anything else on it will get NPE. + GetAllFees(ctx context.Context) ([]entities.Market, error) } type VRStore interface { @@ -109,13 +111,15 @@ func (s *PSvc) GetPartyStats(ctx context.Context, partyID string, markets []stri return nil, err } // then get the markets: - mkts, err := s.mkt.GetByIDs(ctx, markets) + var mkts []entities.Market + if len(markets) > 0 { + mkts, err = s.mkt.GetByIDs(ctx, markets) + } else { + mkts, err = s.mkt.GetAllFees(ctx) + } if err != nil { return nil, err } - if len(mkts) == 0 { - return nil, fmt.Errorf("no valid markets provided") - } lastE := uint64(epoch.ID - 1) data := &v2.GetPartyDiscountStatsResponse{} diff --git a/datanode/sqlstore/markets.go b/datanode/sqlstore/markets.go index c7e8dd0479..fe8e87c207 100644 --- a/datanode/sqlstore/markets.go +++ b/datanode/sqlstore/markets.go @@ -250,6 +250,17 @@ func (m *Markets) GetByTxHash(ctx context.Context, txHash entities.TxHash) ([]en return markets, m.wrapE(err) } +// GetAllFees returns fee information for all markets. +// it returns a market entity with only id and fee. +// NB: it's not cached nor paged. +func (m *Markets) GetAllFees(ctx context.Context) ([]entities.Market, error) { + markets := make([]entities.Market, 0) + args := make([]interface{}, 0) + query := `select mc.id, mc.fees from markets_current mc where state != 'STATE_REJECTED' AND state != 'STATE_SETTLED' AND state != 'STATE_CLOSED' order by mc.id` + err := pgxscan.Select(ctx, m.ConnectionSource, &markets, query, args...) + return markets, err +} + func (m *Markets) GetAllPaged(ctx context.Context, marketID string, pagination entities.CursorPagination, includeSettled bool) ([]entities.Market, entities.PageInfo, error) { key := newCacheKey(marketID, pagination, includeSettled) m.allCacheLock.Lock() diff --git a/datanode/sqlstore/markets_test.go b/datanode/sqlstore/markets_test.go index 28bb945410..bbb58a925e 100644 --- a/datanode/sqlstore/markets_test.go +++ b/datanode/sqlstore/markets_test.go @@ -49,6 +49,67 @@ func TestMarkets_Get(t *testing.T) { t.Run("GetByID should return a perpetual market if it exists", getByIDShouldReturnAPerpetualMarketIfItExists) } +func TestGetAllFees(t *testing.T) { + bs, md := setupMarketsTest(t) + + ctx := tempTransaction(t) + + block := addTestBlock(t, ctx, bs) + + market := entities.Market{ + ID: "deadbeef", + TxHash: generateTxHash(), + VegaTime: block.VegaTime, + State: entities.MarketStateActive, + Fees: entities.Fees{ + Factors: &entities.FeeFactors{ + MakerFee: "0.1", + InfrastructureFee: "0.2", + LiquidityFee: "0.3", + BuyBackFee: "0.4", + TreasuryFee: "0.5", + }, + }, + } + err := md.Upsert(ctx, &market) + require.NoError(t, err) + + market2 := entities.Market{ + ID: "beefdead", + TxHash: generateTxHash(), + VegaTime: block.VegaTime, + State: entities.MarketStateActive, + Fees: entities.Fees{ + Factors: &entities.FeeFactors{ + MakerFee: "0.5", + InfrastructureFee: "0.4", + LiquidityFee: "0.3", + BuyBackFee: "0.2", + TreasuryFee: "0.1", + }, + }, + } + err = md.Upsert(ctx, &market2) + require.NoError(t, err, "Saving market entity to database") + + mkts, err := md.GetAllFees(ctx) + require.NoError(t, err) + require.Equal(t, 2, len(mkts)) + + require.Equal(t, "beefdead", mkts[0].ID.String()) + require.Equal(t, "0.5", mkts[0].Fees.Factors.MakerFee) + require.Equal(t, "0.4", mkts[0].Fees.Factors.InfrastructureFee) + require.Equal(t, "0.3", mkts[0].Fees.Factors.LiquidityFee) + require.Equal(t, "0.2", mkts[0].Fees.Factors.BuyBackFee) + require.Equal(t, "0.1", mkts[0].Fees.Factors.TreasuryFee) + require.Equal(t, "deadbeef", mkts[1].ID.String()) + require.Equal(t, "0.1", mkts[1].Fees.Factors.MakerFee) + require.Equal(t, "0.2", mkts[1].Fees.Factors.InfrastructureFee) + require.Equal(t, "0.3", mkts[1].Fees.Factors.LiquidityFee) + require.Equal(t, "0.4", mkts[1].Fees.Factors.BuyBackFee) + require.Equal(t, "0.5", mkts[1].Fees.Factors.TreasuryFee) +} + func getByIDShouldReturnTheRequestedMarketIfItExists(t *testing.T) { bs, md := setupMarketsTest(t)