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 }