code.vegaprotocol.io/vega@v0.79.0/core/coreapi/services/accounts.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package services
    17  
    18  import (
    19  	"context"
    20  	"sync"
    21  
    22  	"code.vegaprotocol.io/vega/core/events"
    23  	"code.vegaprotocol.io/vega/core/subscribers"
    24  	vegapb "code.vegaprotocol.io/vega/protos/vega"
    25  	coreapipb "code.vegaprotocol.io/vega/protos/vega/api/v1"
    26  )
    27  
    28  type accountE interface {
    29  	events.Event
    30  	Account() vegapb.Account
    31  }
    32  
    33  type Accounts struct {
    34  	*subscribers.Base
    35  
    36  	mu sync.RWMutex
    37  	// parties -> accounts id -> accounts
    38  	parties map[string]map[string]vegapb.Account
    39  	// markets id -> accounts id -> account
    40  	markets map[string]map[string]vegapb.Account
    41  	// global accounts id -> account
    42  	globals map[string]vegapb.Account
    43  }
    44  
    45  func NewAccounts(ctx context.Context) *Accounts {
    46  	return &Accounts{
    47  		Base:    subscribers.NewBase(ctx, 1000, true),
    48  		parties: map[string]map[string]vegapb.Account{},
    49  		markets: map[string]map[string]vegapb.Account{},
    50  		globals: map[string]vegapb.Account{},
    51  	}
    52  }
    53  
    54  func (a *Accounts) Push(evts ...events.Event) {
    55  	if len(evts) == 0 {
    56  		return
    57  	}
    58  	a.mu.Lock()
    59  	defer a.mu.Unlock()
    60  	for _, e := range evts {
    61  		switch acc := e.(type) {
    62  		case accountE:
    63  			a.addAccount(acc.Account())
    64  		}
    65  	}
    66  }
    67  
    68  func (a *Accounts) List(party, market string) []*coreapipb.Account {
    69  	a.mu.RLock()
    70  	defer a.mu.RUnlock()
    71  	if len(party) > 0 {
    72  		return a.getPartyAccounts(party, market)
    73  	}
    74  	if len(market) > 0 {
    75  		return a.getMarketAccounts(market)
    76  	}
    77  	return a.getGlobalAccounts()
    78  }
    79  
    80  func (a *Accounts) Types() []events.Type {
    81  	return []events.Type{
    82  		events.AccountEvent,
    83  	}
    84  }
    85  
    86  func (a *Accounts) getPartyAccounts(party, market string) []*coreapipb.Account {
    87  	accs, ok := a.parties[party]
    88  	if !ok {
    89  		return nil
    90  	}
    91  
    92  	// at least one
    93  	out := make([]*coreapipb.Account, 0, 1)
    94  	for _, v := range accs {
    95  		if len(market) > 0 && v.MarketId != market {
    96  			continue
    97  		}
    98  		out = append(out, toAccount(v))
    99  	}
   100  
   101  	return out
   102  }
   103  
   104  func (a *Accounts) getMarketAccounts(market string) []*coreapipb.Account {
   105  	accs, ok := a.markets[market]
   106  	if !ok {
   107  		return nil
   108  	}
   109  
   110  	out := make([]*coreapipb.Account, 0, len(accs))
   111  	for _, v := range accs {
   112  		out = append(out, toAccount(v))
   113  	}
   114  
   115  	return out
   116  }
   117  
   118  func (a *Accounts) getGlobalAccounts() []*coreapipb.Account {
   119  	out := make([]*coreapipb.Account, 0, len(a.globals))
   120  	for _, v := range a.globals {
   121  		out = append(out, toAccount(v))
   122  	}
   123  
   124  	return out
   125  }
   126  
   127  func (a *Accounts) addAccount(acc vegapb.Account) {
   128  	if acc.MarketId == "!" && acc.Owner == "*" {
   129  		a.globals[acc.Id] = acc
   130  	}
   131  
   132  	if acc.Owner != "*" {
   133  		a.addPartyAccount(acc)
   134  	}
   135  
   136  	a.addMarketAccount(acc)
   137  }
   138  
   139  func (a *Accounts) addPartyAccount(acc vegapb.Account) {
   140  	accs, ok := a.parties[acc.Owner]
   141  	if !ok {
   142  		accs = map[string]vegapb.Account{}
   143  		a.parties[acc.Owner] = accs
   144  	}
   145  	accs[acc.Id] = acc
   146  }
   147  
   148  func (a *Accounts) addMarketAccount(acc vegapb.Account) {
   149  	accs, ok := a.parties[acc.MarketId]
   150  	if !ok {
   151  		accs = map[string]vegapb.Account{}
   152  		a.parties[acc.MarketId] = accs
   153  	}
   154  	accs[acc.Id] = acc
   155  }
   156  
   157  func toAccount(acc vegapb.Account) *coreapipb.Account {
   158  	market := ""
   159  	if acc.MarketId != "!" {
   160  		market = acc.MarketId
   161  	}
   162  	owner := "0000000000000000000000000000000000000000000000000000000000000000"
   163  	if acc.Owner != "*" {
   164  		owner = acc.Owner
   165  	}
   166  
   167  	return &coreapipb.Account{
   168  		Party:   owner,
   169  		Market:  market,
   170  		Balance: acc.Balance,
   171  		Asset:   acc.Asset,
   172  		Type:    acc.Type.String(),
   173  	}
   174  }