pyaver.market

  1from solana.rpc.async_api import AsyncClient
  2from .constants import MAX_ITERATIONS_FOR_CONSUME_EVENTS
  3from .event_queue import load_all_event_queues, prepare_user_accounts_list
  4from .aver_client import AverClient
  5from solana.publickey import PublicKey
  6from solana.keypair import Keypair
  7from .enums import Fill, MarketStatus
  8from .constants import AVER_MARKET_AUTHORITY, AVER_PROGRAM_ID
  9from .utils import load_multiple_bytes_data, sign_and_send_transaction_instructions, parse_market_store, parse_market_state
 10from .data_classes import MarketState, MarketStoreState, OrderbookAccountsState
 11from .orderbook import Orderbook
 12from solana.transaction import AccountMeta
 13from .slab import Slab
 14from anchorpy import Context
 15from spl.token.instructions import get_associated_token_address
 16from spl.token.constants import TOKEN_PROGRAM_ID
 17from solana.rpc.types import TxOpts
 18
 19class AverMarket():
 20    """
 21    AverMarket object
 22
 23    Contains information, references and and orderbooks on a particular market
 24    """
 25
 26    market_pubkey: PublicKey
 27    """Market pubkey"""
 28    market_state: MarketState
 29    """MarketState object holding data about the market"""
 30    market_store_state: MarketStoreState
 31    """MarketStoreStateobject holding data about the market required during active trading. 
 32    
 33    This does not exist if the market has stopped trading, voided or resolved"""
 34    orderbooks: list[Orderbook]
 35    """
 36    Ordered list of Orderbooks for this market.
 37
 38    Note: Binary (two-outcome0) markets only have 1 orderbook.
 39    """
 40    aver_client: AverClient
 41    """AverClient object"""
 42
 43    def __init__(
 44        self, 
 45        aver_client: AverClient, 
 46        market_pubkey: PublicKey,
 47        market_state: MarketState,
 48        market_store_state: MarketStoreState = None,
 49        orderbooks: list[Orderbook] = None,
 50        ):
 51        """
 52        Initialise an AverMarket object. Do not use this function; use AverMarket.load() instead.
 53
 54        Args:
 55            aver_client (AverClient): AverClient object
 56            market_pubkey (PublicKey): Market public key
 57            market_state (MarketState): MarketState object
 58            market_store_state (MarketStoreState, optional): MarketStoreState object. Defaults to None.
 59            orderbooks (list[Orderbook], optional): List of Orderbook objects. Defaults to None.
 60        """
 61        self.market_pubkey = market_pubkey
 62        self.market_state = market_state
 63        self.market_store_state = market_store_state
 64        self.orderbooks = orderbooks
 65        self.aver_client = aver_client
 66
 67        if(market_state.number_of_outcomes == 2 and orderbooks is not None and len(orderbooks) == 1):
 68            orderbooks.append(orderbooks[0].invert())
 69    
 70    @staticmethod
 71    async def load(aver_client: AverClient, market_pubkey: PublicKey):
 72        """
 73        Initialises an AverMarket object
 74
 75        To refresh data on an already loaded market use src.refresh.refresh_markets()
 76
 77        Args:
 78            aver_client (AverClient): AverClient object
 79            market_pubkey (PublicKey): Market public key
 80
 81        Returns:
 82            AverMarket: AverMarket object
 83        """
 84        market_state_and_store = await AverMarket.load_market_state_and_store(aver_client, market_pubkey)
 85        market_state: MarketState = market_state_and_store['market_states'][0]
 86        market_store_state = None
 87        orderbooks = None
 88        is_market_status_closed = AverMarket.is_market_status_closed(market_state.market_status)
 89        market_store_state: MarketStoreState = market_state_and_store['market_stores'][0]
 90
 91        if(not is_market_status_closed):
 92            orderbooks = await AverMarket.get_orderbooks_from_orderbook_accounts(
 93                aver_client.provider.connection,
 94                market_store_state.orderbook_accounts,
 95                [market_state.decimals] * len(market_store_state.orderbook_accounts)
 96            )
 97
 98        return AverMarket(aver_client, market_pubkey, market_state, market_store_state, orderbooks)
 99
100    @staticmethod
101    async def load_multiple(aver_client: AverClient, market_pubkeys: list[PublicKey]):
102        """
103        Initialises multiple AverMarket objects
104
105        This method is quicker that using Market.load() multiple times
106
107        To refresh data on already loaded markets use src.refresh.refresh_multiple_markets()
108
109        Args:
110            aver_client (AverClient): AverClient object
111            market_pubkeys (list[PublicKey]): List of Market public keys
112
113        Returns:
114            list[AverMarket]: List of AverMarket objects
115        """
116        market_states_and_stores = await AverMarket.load_multiple_market_states_and_stores(aver_client, market_pubkeys)
117        market_states: list[MarketState] = market_states_and_stores['market_states']
118
119        are_market_statuses_closed = []
120        for market_state in market_states:
121            are_market_statuses_closed.append(AverMarket.is_market_status_closed(market_state.market_status))
122
123        market_stores: list[MarketStoreState] = market_states_and_stores['market_stores']
124
125        orderbooks_market_list = await AverMarket.get_orderbooks_from_orderbook_accounts_multiple_markets(
126            aver_client.provider.connection,
127            market_states,
128            market_stores,
129            are_market_statuses_closed,
130        )
131        
132        markets: list[AverMarket] = []
133        for index, market_pubkey in enumerate(market_pubkeys):
134            market = AverMarket(
135                aver_client, 
136                market_pubkey,
137                market_states[index], 
138                market_stores[index], 
139                orderbooks_market_list[index]
140                )
141            markets.append(market)
142        
143        return markets
144
145    @staticmethod
146    async def load_market_state(aver_client: AverClient, market_pubkey: PublicKey) -> MarketState:
147        """
148        Loads onchain data for a MarketState
149
150        Args:
151            aver_client (AverClient): AverClient object
152            market_pubkey (PublicKey): Market public key
153
154        Returns:
155            MarketState: MarketState object
156        """
157        res = await aver_client.program.account['Market'].fetch(market_pubkey)
158        return res
159 
160    @staticmethod
161    async def load_multiple_market_states(aver_client: AverClient, market_pubkeys: list[PublicKey]) -> list[MarketState]:
162        """
163        Loads onchain data for multiple MarketStates
164
165        Args:
166            aver_client (AverClient): AverClient object
167            market_pubkeys (list[PublicKey]): List of market public keys
168
169        Returns:
170            list[MarketState]: List of MarketState objects
171        """
172        res = await aver_client.program.account['Market'].fetch_multiple(market_pubkeys)
173        return res
174   
175    @staticmethod
176    async def load_market_state_and_store(aver_client: AverClient, market_pubkey: PublicKey):
177        """
178        Loads onchain data for multiple MarketStates and MarketStoreStates at once
179
180        Args:
181            aver_client (AverClient): AverClient object
182            market_pubkey (PublicKey]: Market public key
183
184        Returns:
185            dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores
186        """
187        return await AverMarket.load_multiple_market_states_and_stores(aver_client, [market_pubkey])
188
189    @staticmethod
190    async def load_multiple_market_states_and_stores(aver_client: AverClient, market_pubkeys: list[PublicKey]):
191        """
192        Loads onchain data for multiple MarketStates and MarketStoreStates at once
193
194        Args:
195            aver_client (AverClient): AverClient object
196            market_pubkeys (list[PublicKey]): List of market public keys
197
198        Returns:
199            dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores
200        """
201        market_store_pubkeys = [AverMarket.derive_market_store_pubkey_and_bump(m, AVER_PROGRAM_ID)[0] for m in market_pubkeys]
202
203        data = await load_multiple_bytes_data(aver_client.connection, market_pubkeys + market_store_pubkeys)
204        market_states_data = data[0:len(market_pubkeys)]
205        market_stores_data = data[len(market_pubkeys):]
206
207        market_states = [parse_market_state(d, aver_client) for d in market_states_data]
208        market_stores = [parse_market_store(d, aver_client) if d is not None else None for d in market_stores_data]
209
210        return {'market_states': market_states, 'market_stores': market_stores}
211
212    @staticmethod
213    def derive_market_store_pubkey_and_bump(market_pubkey: PublicKey, program_id: PublicKey = AVER_PROGRAM_ID):
214        """
215        Derives PDA (Program Derived Account) for MarketStore public key.
216        MarketStore account addresses are derived deterministically using the market's pubkey.
217
218        Args:
219            market_pubkey (PublicKey): Market public key
220            program_id (PublicKey, optional): Program public key. Defaults to AVER_PROGRAM_ID.
221
222        Returns:
223            PublicKey: MarketStore public key
224        """
225        return PublicKey.find_program_address(
226            [bytes('market-store', 'utf-8'), bytes(market_pubkey)], 
227            program_id
228        )
229
230    @staticmethod
231    def get_markets_from_account_states(
232        aver_client: AverClient,
233        market_pubkeys: list[PublicKey], 
234        market_states: list[MarketState], 
235        market_stores: list[MarketStoreState],
236        slabs: list[Slab],
237        ):
238        """
239        Returns multiple AverMarket objects from their respective MarketStates, stores and orderbook objects
240
241        Used in refresh.py
242
243        Args:
244            aver_client (AverClient): AverClient object
245            market_pubkeys (list[PublicKey]): List of market public keys
246            market_states (list[MarketState]): List of MarketState objects
247            market_stores (list[MarketStoreState]): List of MarketStoreState objects
248            slabs (list[Slab]): List of slab objects (used in orderbooks)
249
250        Returns:
251            lst[AverMarket]: List of AverMarket objects
252        """
253        slab_position_counter = 0
254        all_orderbooks = []
255        for j, market_store in enumerate(market_stores):
256            all_orderbooks_for_market = []
257            if(market_store is None):
258                all_orderbooks.append(None)
259                continue
260            for i, orderbook in enumerate(market_store.orderbook_accounts):
261                orderbook = Orderbook(
262                    orderbook.orderbook, 
263                    slabs[slab_position_counter + i * 2],
264                    slabs[slab_position_counter + i * 2 + 1],
265                    orderbook.bids,
266                    orderbook.asks,
267                    market_states[j].decimals
268                    )
269                all_orderbooks_for_market.append(orderbook)
270            slab_position_counter += len(market_store.orderbook_accounts) * 2
271            all_orderbooks.append(all_orderbooks_for_market)
272        
273        markets: list[AverMarket] = []
274        for i, m in enumerate(market_pubkeys):
275            markets.append(AverMarket(
276                aver_client, 
277                m, 
278                market_states[i],
279                market_stores[i],
280                all_orderbooks[i]
281                )
282            )
283
284        return markets
285
286
287    @staticmethod
288    async def load_market_store_state(
289        aver_client: AverClient, 
290        is_market_status_closed: bool,
291        market_store_pubkey: PublicKey, 
292        ) -> MarketStoreState:
293        """
294        Loads onchain data for a MarketStore State
295
296        Args:
297            aver_client (AverClient): AverClient object
298            is_market_status_closed (bool): True if market status is closed, voided or resolved
299            market_store_pubkey (PublicKey): MarketStore public key
300
301        Returns:
302            MarketStoreState: MarketStoreStateobject
303        """
304        #Closed markets do not have orderbooks
305        if(is_market_status_closed):
306            return None
307        res = await aver_client.program.account['MarketStore'].fetch(market_store_pubkey)
308        return res
309
310
311    @staticmethod
312    async def load_multiple_market_store_states(
313        aver_client: AverClient, 
314        market_store_pubkeys: list[PublicKey], 
315        ) -> list[MarketStoreState]:
316        """
317        Loads onchain data for multiple MarketStore States
318
319        Args:
320            aver_client (AverClient): AverClient object
321            market_store_pubkeys (list[PublicKey]): List of MarketStore public keys
322
323        Returns:
324            list[MarketStoreState]: List of MarketStore public keys
325        """
326        res = await aver_client.program.account['MarketStore'].fetch_multiple(market_store_pubkeys)
327        return res       
328
329    @staticmethod
330    def is_market_status_closed(market_status: MarketStatus):
331        """
332        Checks if a market no longer in a trading status, and therefore will have no Orderbook or MarketStore accounts.
333        Note: Once trading has ceased for a market, these accounts are closed.
334
335        Args:
336            market_status (MarketStatus): Market status (find in MarketState object)
337
338        Returns:
339            bool: Market status closed
340        """
341        return market_status in [MarketStatus.CEASED_CRANKED_CLOSED, MarketStatus.RESOLVED, MarketStatus.VOIDED]
342
343    @staticmethod
344    async def get_orderbooks_from_orderbook_accounts(
345        conn: AsyncClient, 
346        orderbook_accounts: list[OrderbookAccountsState],
347        decimals_list: list[int]
348        ) -> list[Orderbook]:
349        """
350        Returns Orderbook objects from Orderbook Account objects, by fetching and parsing. 
351
352        Args:
353            conn (AsyncClient): Solana AsyncClient object
354            orderbook_accounts (list[OrderbookAccountsState]): List of orderbook account objects
355            decimals_list (list[int]): List of decimal precision for each orderbook account state. Variable normally found in MarketState object
356
357        Raises:
358            Exception: Decimals list and orderbook accounts do not have the same length
359
360        Returns:
361            list[Orderbook]: List of orderbook objects
362        """
363        if(len(decimals_list) != len(orderbook_accounts)):
364            raise Exception('decimals_list and orderbook_accounts should have the same length')
365        
366        all_bids_and_asks_accounts = []
367        for o in orderbook_accounts:
368            all_bids_and_asks_accounts.append(o.bids)
369            all_bids_and_asks_accounts.append(o.asks)
370
371        
372        all_slabs = await Orderbook.load_multiple_slabs(conn, all_bids_and_asks_accounts)
373        orderbooks = []
374
375        for i, o in enumerate(orderbook_accounts):
376            orderbook = Orderbook(
377                o.orderbook, 
378                all_slabs[i*2], 
379                all_slabs[i*2 + 1], 
380                o.bids,o.asks,
381                decimals_list[i]
382                )
383            orderbooks.append(orderbook)
384        return orderbooks
385
386
387
388    @staticmethod
389    async def get_orderbooks_from_orderbook_accounts_multiple_markets(
390        conn: AsyncClient,
391        market_states: list[MarketState],
392        market_stores: list[MarketStoreState],
393        are_market_statuses_closed: list[bool],
394    ):
395        """
396        Returns Orderbook objects from MarketState and MarketStoreStateobjects,
397        by fetching and parsing for multiple markets.
398
399        Use when fetching orderbooks for multiple markets 
400
401        Args:
402            conn (AsyncClient): Solana AsyncClient object
403            market_states (list[MarketState]): List of MarketState objects
404            market_stores (list[MarketStoreState]): List of MarketStoreStateobjects
405            are_market_statuses_closed (list[bool]): Lists if each market is closed or not
406
407        Returns:
408            list[list[Orderbook]]: List of orderbooks for each market
409        """
410        #Create list of accounts and the decimals for each account
411        orderbook_accounts = []
412        decimals_list = []
413        for index, market_store in enumerate(market_stores):
414            if(market_store is None):
415                continue
416            orderbook_accounts.extend(market_store.orderbook_accounts)
417            for i in range(len(market_store.orderbook_accounts)):
418                decimals_list.append(market_states[index].decimals)
419        
420        #Load all orderbooks
421        all_orderbooks: list[Orderbook] = await AverMarket.get_orderbooks_from_orderbook_accounts(conn, orderbook_accounts, decimals_list)
422        orderbooks_market_list = []
423
424        #Create a list for each market we received. The list contains all orderbooks for that market
425        for index, market_state in enumerate(market_states):
426            number_of_outcomes = market_state.number_of_outcomes
427            orderbooks = []
428            #Market is closed
429            if(are_market_statuses_closed[index]):
430                orderbooks_market_list.append(None)
431                continue
432            #Binary markets only have 1 orderbook
433            if(number_of_outcomes == 2):
434                orderbooks.append(all_orderbooks.pop(0))
435            else:
436                orderbooks = []
437                for i in range(number_of_outcomes):
438                    orderbooks.append(all_orderbooks.pop(0))
439            orderbooks_market_list.append(orderbooks)
440        
441        return orderbooks_market_list
442
443    
444    def make_sweep_fees_instruction(self):
445        """
446        Creates instruction to sweeps fees and sends to relevant accounts
447
448        Returns TransactionInstruction object only. Does not send transaction.
449
450        Returns:
451            TransactionInstruction: TransactionInstruction object
452        """
453        quote_token = self.aver_client.quote_token
454        third_party_vault_authority, bump = PublicKey.find_program_address(
455            [b"third-party-token-vault", bytes(quote_token)], AVER_PROGRAM_ID)
456
457        third_party_vault_token_account = get_associated_token_address(
458            third_party_vault_authority, quote_token)
459
460        aver_quote_token_account = get_associated_token_address(
461            AVER_MARKET_AUTHORITY, quote_token
462        )
463
464        return self.aver_client.program.instruction["sweep_fees"](
465            ctx=Context(
466                accounts={
467                    "market": self.market_pubkey,
468                    "quote_vault": self.market_state.quote_vault,
469                    "vault_authority": self.market_state.vault_authority,
470                    "third_party_token_vault": third_party_vault_token_account,
471                    "aver_quote_token_account": aver_quote_token_account,
472                    "spl_token_program": TOKEN_PROGRAM_ID,
473                },
474                signers=[],
475            ),
476        )
477    
478    async def sweep_fees(self, fee_payer: Keypair = None, send_options: TxOpts = None,):
479        """
480        Sweeps fees and sends to relevant accounts
481
482        Sends instructions on chain
483
484        Args:
485            fee_payer (Keypair): Pays transaction fees. Defaults to AverClient wallet
486            send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
487
488        Returns:
489            RPCResponse: Response
490        """
491        if(fee_payer == None):
492            fee_payer = self.aver_client.owner
493
494        ix = self.make_sweep_fees_instruction()
495
496        return await sign_and_send_transaction_instructions(
497            self.aver_client,
498            [],
499            fee_payer,
500            [ix],
501            send_options
502        )
503
504    def list_all_pubkeys(self):
505        """
506        Returns all pubkeys used in AverMarket object
507
508        Returns:
509            list[PublicKey]: List of public keys
510        """
511        list_of_pubkeys = [self.market_pubkey, self.market_state.quote_vault, self.market_state.oracle_feed]
512        if not self.is_market_status_closed:
513            for ob in self.orderbooks:
514                list_of_pubkeys += [ob.pubkey, ob.slab_asks_pubkey, ob.slab_asks_pubkey]
515        return list_of_pubkeys
516    
517    async def get_implied_market_status(
518            self
519        ) -> MarketStatus:
520        """
521        Returns what we believe the market status ought to be (rather than what is stored in the market's state on-chain)
522
523        Note: As a fail safe, markets have specified times beyond which the market will react as if it is in another Status until it is formally cranked to that Status.
524        For example, if Solana were to have issues and it was not possible for the market's authority to crank it into In-Play status or to Cease Trading in time,
525        the market would use the System Time as a trigger to treat new requests as if it were in the later Status.
526
527        If Solana clock time is beyond TradingCeaseTime, market is TradingCeased
528        If Solana clock time is beyond InPlayStartTime but before TradingCeaseTime, market is ActiveInPlay
529
530        Returns:
531            MarketStatus: Implied market status
532        """
533        solana_datetime = await self.aver_client.get_system_clock_datetime()
534        if solana_datetime.timestamp() > self.market_state.trading_cease_time:
535            return MarketStatus.TRADING_CEASED
536        if self.market_state.inplay_start_time is not None and solana_datetime.timestamp() > self.market_state.inplay_start_time :
537            return MarketStatus.ACTIVE_IN_PLAY
538        return self.market_state.market_status
539
540    async def crank_market(
541            self,
542            outcome_idxs: list[int] = None,
543            reward_target: PublicKey = None,
544            payer: Keypair = None,
545        ):
546        """
547        Refresh market before cranking
548        If no outcome_idx are passed, all outcomes are cranked if they meet the criteria to be cranked.
549        """
550        if outcome_idxs == None:
551            # For binary markets, there is only one orderbook
552            outcome_idxs = [idx for idx in range(
553                1 if self.market_state.number_of_outcomes == 2 else self.market_state.number_of_outcomes)]
554        if self.market_state.number_of_outcomes == 2 and (0 in outcome_idxs or 1 in outcome_idxs):
555            outcome_idxs = [0]
556        if reward_target == None:
557            reward_target = self.aver_client.owner.public_key
558        if payer == None:
559            payer = self.aver_client.owner
560
561        # refreshed_market = await refresh_market(self.aver_client, self)
562
563        event_queues = [o.event_queue for o in self.market_store_state.orderbook_accounts]
564        loaded_event_queues = await load_all_event_queues(
565            self.aver_client.provider.connection,
566            event_queues 
567            )
568
569        sig = ''
570        for idx in outcome_idxs:
571            if loaded_event_queues[idx]["header"].count == 0:
572                continue
573
574            print(f'Cranking market {str(self.market_pubkey)} for outcome {idx} - {loaded_event_queues[idx]["header"].count} events left to crank')
575            if loaded_event_queues[idx]['header'].count > 0:
576                user_accounts = []
577                for j, event in enumerate(loaded_event_queues[idx]['nodes']):
578                    if type(event) == Fill:
579                        user_accounts += [event.maker_user_market]
580                    else:  # Out
581                        user_accounts += [event.user_market]
582                    if j == MAX_ITERATIONS_FOR_CONSUME_EVENTS:
583                        break
584                user_accounts = prepare_user_accounts_list(user_accounts)
585                events_to_crank = min(
586                    loaded_event_queues[idx]['header'].count, MAX_ITERATIONS_FOR_CONSUME_EVENTS)
587
588                sig = await self.consume_events(
589                    outcome_idx=idx,
590                    max_iterations=events_to_crank,
591                    user_accounts=user_accounts,
592                    reward_target=reward_target,
593                    payer=payer,
594                )
595
596        return sig
597
598    async def consume_events(
599        self,
600        outcome_idx: int,
601        user_accounts: list[PublicKey],
602        max_iterations: int = None,
603        reward_target: PublicKey = None,
604        payer: Keypair = None,
605    ):
606        """
607        Consume events
608
609        Sends instructions on chain
610
611        Args:
612            outcome_idx (int): index of the outcome
613            user_accounts (list[PublicKey]): List of User Account public keys
614            max_iterations (int, optional): Depth of events to iterate through. Defaults to MAX_ITERATIONS_FOR_CONSUME_EVENTS.
615            reward_target (PublicKey, optional): Target for reward. Defaults to AverClient wallet.
616            payer (Keypair, optional): Fee payer. Defaults to AverClient wallet.
617
618        Returns:
619            Transaction Signature: TransactionSignature object
620        """
621        if reward_target == None:
622            reward_target = self.aver_client.owner.public_key
623        if payer == None:
624            payer = self.aver_client.owner
625        if max_iterations > MAX_ITERATIONS_FOR_CONSUME_EVENTS or max_iterations == None:
626            max_iterations = MAX_ITERATIONS_FOR_CONSUME_EVENTS
627        
628        user_accounts_unsorted = [AccountMeta(
629                pk, False, True) for pk in user_accounts]
630                
631        remaining_accounts = sorted(user_accounts_unsorted, key=lambda account: bytes(account.pubkey))
632
633        return await self.aver_client.program.rpc["consume_events"](
634                max_iterations,
635                outcome_idx,
636                ctx=Context(
637                    accounts={
638                        "market": self.market_pubkey,
639                        "market_store": self.market_state.market_store,
640                        "orderbook": self.market_store_state.orderbook_accounts[outcome_idx].orderbook,
641                        "event_queue": self.market_store_state.orderbook_accounts[outcome_idx].event_queue,
642                        "reward_target": reward_target,
643                    },
644                    remaining_accounts=remaining_accounts,
645                ),
646            )
class AverMarket:
 20class AverMarket():
 21    """
 22    AverMarket object
 23
 24    Contains information, references and and orderbooks on a particular market
 25    """
 26
 27    market_pubkey: PublicKey
 28    """Market pubkey"""
 29    market_state: MarketState
 30    """MarketState object holding data about the market"""
 31    market_store_state: MarketStoreState
 32    """MarketStoreStateobject holding data about the market required during active trading. 
 33    
 34    This does not exist if the market has stopped trading, voided or resolved"""
 35    orderbooks: list[Orderbook]
 36    """
 37    Ordered list of Orderbooks for this market.
 38
 39    Note: Binary (two-outcome0) markets only have 1 orderbook.
 40    """
 41    aver_client: AverClient
 42    """AverClient object"""
 43
 44    def __init__(
 45        self, 
 46        aver_client: AverClient, 
 47        market_pubkey: PublicKey,
 48        market_state: MarketState,
 49        market_store_state: MarketStoreState = None,
 50        orderbooks: list[Orderbook] = None,
 51        ):
 52        """
 53        Initialise an AverMarket object. Do not use this function; use AverMarket.load() instead.
 54
 55        Args:
 56            aver_client (AverClient): AverClient object
 57            market_pubkey (PublicKey): Market public key
 58            market_state (MarketState): MarketState object
 59            market_store_state (MarketStoreState, optional): MarketStoreState object. Defaults to None.
 60            orderbooks (list[Orderbook], optional): List of Orderbook objects. Defaults to None.
 61        """
 62        self.market_pubkey = market_pubkey
 63        self.market_state = market_state
 64        self.market_store_state = market_store_state
 65        self.orderbooks = orderbooks
 66        self.aver_client = aver_client
 67
 68        if(market_state.number_of_outcomes == 2 and orderbooks is not None and len(orderbooks) == 1):
 69            orderbooks.append(orderbooks[0].invert())
 70    
 71    @staticmethod
 72    async def load(aver_client: AverClient, market_pubkey: PublicKey):
 73        """
 74        Initialises an AverMarket object
 75
 76        To refresh data on an already loaded market use src.refresh.refresh_markets()
 77
 78        Args:
 79            aver_client (AverClient): AverClient object
 80            market_pubkey (PublicKey): Market public key
 81
 82        Returns:
 83            AverMarket: AverMarket object
 84        """
 85        market_state_and_store = await AverMarket.load_market_state_and_store(aver_client, market_pubkey)
 86        market_state: MarketState = market_state_and_store['market_states'][0]
 87        market_store_state = None
 88        orderbooks = None
 89        is_market_status_closed = AverMarket.is_market_status_closed(market_state.market_status)
 90        market_store_state: MarketStoreState = market_state_and_store['market_stores'][0]
 91
 92        if(not is_market_status_closed):
 93            orderbooks = await AverMarket.get_orderbooks_from_orderbook_accounts(
 94                aver_client.provider.connection,
 95                market_store_state.orderbook_accounts,
 96                [market_state.decimals] * len(market_store_state.orderbook_accounts)
 97            )
 98
 99        return AverMarket(aver_client, market_pubkey, market_state, market_store_state, orderbooks)
100
101    @staticmethod
102    async def load_multiple(aver_client: AverClient, market_pubkeys: list[PublicKey]):
103        """
104        Initialises multiple AverMarket objects
105
106        This method is quicker that using Market.load() multiple times
107
108        To refresh data on already loaded markets use src.refresh.refresh_multiple_markets()
109
110        Args:
111            aver_client (AverClient): AverClient object
112            market_pubkeys (list[PublicKey]): List of Market public keys
113
114        Returns:
115            list[AverMarket]: List of AverMarket objects
116        """
117        market_states_and_stores = await AverMarket.load_multiple_market_states_and_stores(aver_client, market_pubkeys)
118        market_states: list[MarketState] = market_states_and_stores['market_states']
119
120        are_market_statuses_closed = []
121        for market_state in market_states:
122            are_market_statuses_closed.append(AverMarket.is_market_status_closed(market_state.market_status))
123
124        market_stores: list[MarketStoreState] = market_states_and_stores['market_stores']
125
126        orderbooks_market_list = await AverMarket.get_orderbooks_from_orderbook_accounts_multiple_markets(
127            aver_client.provider.connection,
128            market_states,
129            market_stores,
130            are_market_statuses_closed,
131        )
132        
133        markets: list[AverMarket] = []
134        for index, market_pubkey in enumerate(market_pubkeys):
135            market = AverMarket(
136                aver_client, 
137                market_pubkey,
138                market_states[index], 
139                market_stores[index], 
140                orderbooks_market_list[index]
141                )
142            markets.append(market)
143        
144        return markets
145
146    @staticmethod
147    async def load_market_state(aver_client: AverClient, market_pubkey: PublicKey) -> MarketState:
148        """
149        Loads onchain data for a MarketState
150
151        Args:
152            aver_client (AverClient): AverClient object
153            market_pubkey (PublicKey): Market public key
154
155        Returns:
156            MarketState: MarketState object
157        """
158        res = await aver_client.program.account['Market'].fetch(market_pubkey)
159        return res
160 
161    @staticmethod
162    async def load_multiple_market_states(aver_client: AverClient, market_pubkeys: list[PublicKey]) -> list[MarketState]:
163        """
164        Loads onchain data for multiple MarketStates
165
166        Args:
167            aver_client (AverClient): AverClient object
168            market_pubkeys (list[PublicKey]): List of market public keys
169
170        Returns:
171            list[MarketState]: List of MarketState objects
172        """
173        res = await aver_client.program.account['Market'].fetch_multiple(market_pubkeys)
174        return res
175   
176    @staticmethod
177    async def load_market_state_and_store(aver_client: AverClient, market_pubkey: PublicKey):
178        """
179        Loads onchain data for multiple MarketStates and MarketStoreStates at once
180
181        Args:
182            aver_client (AverClient): AverClient object
183            market_pubkey (PublicKey]: Market public key
184
185        Returns:
186            dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores
187        """
188        return await AverMarket.load_multiple_market_states_and_stores(aver_client, [market_pubkey])
189
190    @staticmethod
191    async def load_multiple_market_states_and_stores(aver_client: AverClient, market_pubkeys: list[PublicKey]):
192        """
193        Loads onchain data for multiple MarketStates and MarketStoreStates at once
194
195        Args:
196            aver_client (AverClient): AverClient object
197            market_pubkeys (list[PublicKey]): List of market public keys
198
199        Returns:
200            dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores
201        """
202        market_store_pubkeys = [AverMarket.derive_market_store_pubkey_and_bump(m, AVER_PROGRAM_ID)[0] for m in market_pubkeys]
203
204        data = await load_multiple_bytes_data(aver_client.connection, market_pubkeys + market_store_pubkeys)
205        market_states_data = data[0:len(market_pubkeys)]
206        market_stores_data = data[len(market_pubkeys):]
207
208        market_states = [parse_market_state(d, aver_client) for d in market_states_data]
209        market_stores = [parse_market_store(d, aver_client) if d is not None else None for d in market_stores_data]
210
211        return {'market_states': market_states, 'market_stores': market_stores}
212
213    @staticmethod
214    def derive_market_store_pubkey_and_bump(market_pubkey: PublicKey, program_id: PublicKey = AVER_PROGRAM_ID):
215        """
216        Derives PDA (Program Derived Account) for MarketStore public key.
217        MarketStore account addresses are derived deterministically using the market's pubkey.
218
219        Args:
220            market_pubkey (PublicKey): Market public key
221            program_id (PublicKey, optional): Program public key. Defaults to AVER_PROGRAM_ID.
222
223        Returns:
224            PublicKey: MarketStore public key
225        """
226        return PublicKey.find_program_address(
227            [bytes('market-store', 'utf-8'), bytes(market_pubkey)], 
228            program_id
229        )
230
231    @staticmethod
232    def get_markets_from_account_states(
233        aver_client: AverClient,
234        market_pubkeys: list[PublicKey], 
235        market_states: list[MarketState], 
236        market_stores: list[MarketStoreState],
237        slabs: list[Slab],
238        ):
239        """
240        Returns multiple AverMarket objects from their respective MarketStates, stores and orderbook objects
241
242        Used in refresh.py
243
244        Args:
245            aver_client (AverClient): AverClient object
246            market_pubkeys (list[PublicKey]): List of market public keys
247            market_states (list[MarketState]): List of MarketState objects
248            market_stores (list[MarketStoreState]): List of MarketStoreState objects
249            slabs (list[Slab]): List of slab objects (used in orderbooks)
250
251        Returns:
252            lst[AverMarket]: List of AverMarket objects
253        """
254        slab_position_counter = 0
255        all_orderbooks = []
256        for j, market_store in enumerate(market_stores):
257            all_orderbooks_for_market = []
258            if(market_store is None):
259                all_orderbooks.append(None)
260                continue
261            for i, orderbook in enumerate(market_store.orderbook_accounts):
262                orderbook = Orderbook(
263                    orderbook.orderbook, 
264                    slabs[slab_position_counter + i * 2],
265                    slabs[slab_position_counter + i * 2 + 1],
266                    orderbook.bids,
267                    orderbook.asks,
268                    market_states[j].decimals
269                    )
270                all_orderbooks_for_market.append(orderbook)
271            slab_position_counter += len(market_store.orderbook_accounts) * 2
272            all_orderbooks.append(all_orderbooks_for_market)
273        
274        markets: list[AverMarket] = []
275        for i, m in enumerate(market_pubkeys):
276            markets.append(AverMarket(
277                aver_client, 
278                m, 
279                market_states[i],
280                market_stores[i],
281                all_orderbooks[i]
282                )
283            )
284
285        return markets
286
287
288    @staticmethod
289    async def load_market_store_state(
290        aver_client: AverClient, 
291        is_market_status_closed: bool,
292        market_store_pubkey: PublicKey, 
293        ) -> MarketStoreState:
294        """
295        Loads onchain data for a MarketStore State
296
297        Args:
298            aver_client (AverClient): AverClient object
299            is_market_status_closed (bool): True if market status is closed, voided or resolved
300            market_store_pubkey (PublicKey): MarketStore public key
301
302        Returns:
303            MarketStoreState: MarketStoreStateobject
304        """
305        #Closed markets do not have orderbooks
306        if(is_market_status_closed):
307            return None
308        res = await aver_client.program.account['MarketStore'].fetch(market_store_pubkey)
309        return res
310
311
312    @staticmethod
313    async def load_multiple_market_store_states(
314        aver_client: AverClient, 
315        market_store_pubkeys: list[PublicKey], 
316        ) -> list[MarketStoreState]:
317        """
318        Loads onchain data for multiple MarketStore States
319
320        Args:
321            aver_client (AverClient): AverClient object
322            market_store_pubkeys (list[PublicKey]): List of MarketStore public keys
323
324        Returns:
325            list[MarketStoreState]: List of MarketStore public keys
326        """
327        res = await aver_client.program.account['MarketStore'].fetch_multiple(market_store_pubkeys)
328        return res       
329
330    @staticmethod
331    def is_market_status_closed(market_status: MarketStatus):
332        """
333        Checks if a market no longer in a trading status, and therefore will have no Orderbook or MarketStore accounts.
334        Note: Once trading has ceased for a market, these accounts are closed.
335
336        Args:
337            market_status (MarketStatus): Market status (find in MarketState object)
338
339        Returns:
340            bool: Market status closed
341        """
342        return market_status in [MarketStatus.CEASED_CRANKED_CLOSED, MarketStatus.RESOLVED, MarketStatus.VOIDED]
343
344    @staticmethod
345    async def get_orderbooks_from_orderbook_accounts(
346        conn: AsyncClient, 
347        orderbook_accounts: list[OrderbookAccountsState],
348        decimals_list: list[int]
349        ) -> list[Orderbook]:
350        """
351        Returns Orderbook objects from Orderbook Account objects, by fetching and parsing. 
352
353        Args:
354            conn (AsyncClient): Solana AsyncClient object
355            orderbook_accounts (list[OrderbookAccountsState]): List of orderbook account objects
356            decimals_list (list[int]): List of decimal precision for each orderbook account state. Variable normally found in MarketState object
357
358        Raises:
359            Exception: Decimals list and orderbook accounts do not have the same length
360
361        Returns:
362            list[Orderbook]: List of orderbook objects
363        """
364        if(len(decimals_list) != len(orderbook_accounts)):
365            raise Exception('decimals_list and orderbook_accounts should have the same length')
366        
367        all_bids_and_asks_accounts = []
368        for o in orderbook_accounts:
369            all_bids_and_asks_accounts.append(o.bids)
370            all_bids_and_asks_accounts.append(o.asks)
371
372        
373        all_slabs = await Orderbook.load_multiple_slabs(conn, all_bids_and_asks_accounts)
374        orderbooks = []
375
376        for i, o in enumerate(orderbook_accounts):
377            orderbook = Orderbook(
378                o.orderbook, 
379                all_slabs[i*2], 
380                all_slabs[i*2 + 1], 
381                o.bids,o.asks,
382                decimals_list[i]
383                )
384            orderbooks.append(orderbook)
385        return orderbooks
386
387
388
389    @staticmethod
390    async def get_orderbooks_from_orderbook_accounts_multiple_markets(
391        conn: AsyncClient,
392        market_states: list[MarketState],
393        market_stores: list[MarketStoreState],
394        are_market_statuses_closed: list[bool],
395    ):
396        """
397        Returns Orderbook objects from MarketState and MarketStoreStateobjects,
398        by fetching and parsing for multiple markets.
399
400        Use when fetching orderbooks for multiple markets 
401
402        Args:
403            conn (AsyncClient): Solana AsyncClient object
404            market_states (list[MarketState]): List of MarketState objects
405            market_stores (list[MarketStoreState]): List of MarketStoreStateobjects
406            are_market_statuses_closed (list[bool]): Lists if each market is closed or not
407
408        Returns:
409            list[list[Orderbook]]: List of orderbooks for each market
410        """
411        #Create list of accounts and the decimals for each account
412        orderbook_accounts = []
413        decimals_list = []
414        for index, market_store in enumerate(market_stores):
415            if(market_store is None):
416                continue
417            orderbook_accounts.extend(market_store.orderbook_accounts)
418            for i in range(len(market_store.orderbook_accounts)):
419                decimals_list.append(market_states[index].decimals)
420        
421        #Load all orderbooks
422        all_orderbooks: list[Orderbook] = await AverMarket.get_orderbooks_from_orderbook_accounts(conn, orderbook_accounts, decimals_list)
423        orderbooks_market_list = []
424
425        #Create a list for each market we received. The list contains all orderbooks for that market
426        for index, market_state in enumerate(market_states):
427            number_of_outcomes = market_state.number_of_outcomes
428            orderbooks = []
429            #Market is closed
430            if(are_market_statuses_closed[index]):
431                orderbooks_market_list.append(None)
432                continue
433            #Binary markets only have 1 orderbook
434            if(number_of_outcomes == 2):
435                orderbooks.append(all_orderbooks.pop(0))
436            else:
437                orderbooks = []
438                for i in range(number_of_outcomes):
439                    orderbooks.append(all_orderbooks.pop(0))
440            orderbooks_market_list.append(orderbooks)
441        
442        return orderbooks_market_list
443
444    
445    def make_sweep_fees_instruction(self):
446        """
447        Creates instruction to sweeps fees and sends to relevant accounts
448
449        Returns TransactionInstruction object only. Does not send transaction.
450
451        Returns:
452            TransactionInstruction: TransactionInstruction object
453        """
454        quote_token = self.aver_client.quote_token
455        third_party_vault_authority, bump = PublicKey.find_program_address(
456            [b"third-party-token-vault", bytes(quote_token)], AVER_PROGRAM_ID)
457
458        third_party_vault_token_account = get_associated_token_address(
459            third_party_vault_authority, quote_token)
460
461        aver_quote_token_account = get_associated_token_address(
462            AVER_MARKET_AUTHORITY, quote_token
463        )
464
465        return self.aver_client.program.instruction["sweep_fees"](
466            ctx=Context(
467                accounts={
468                    "market": self.market_pubkey,
469                    "quote_vault": self.market_state.quote_vault,
470                    "vault_authority": self.market_state.vault_authority,
471                    "third_party_token_vault": third_party_vault_token_account,
472                    "aver_quote_token_account": aver_quote_token_account,
473                    "spl_token_program": TOKEN_PROGRAM_ID,
474                },
475                signers=[],
476            ),
477        )
478    
479    async def sweep_fees(self, fee_payer: Keypair = None, send_options: TxOpts = None,):
480        """
481        Sweeps fees and sends to relevant accounts
482
483        Sends instructions on chain
484
485        Args:
486            fee_payer (Keypair): Pays transaction fees. Defaults to AverClient wallet
487            send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
488
489        Returns:
490            RPCResponse: Response
491        """
492        if(fee_payer == None):
493            fee_payer = self.aver_client.owner
494
495        ix = self.make_sweep_fees_instruction()
496
497        return await sign_and_send_transaction_instructions(
498            self.aver_client,
499            [],
500            fee_payer,
501            [ix],
502            send_options
503        )
504
505    def list_all_pubkeys(self):
506        """
507        Returns all pubkeys used in AverMarket object
508
509        Returns:
510            list[PublicKey]: List of public keys
511        """
512        list_of_pubkeys = [self.market_pubkey, self.market_state.quote_vault, self.market_state.oracle_feed]
513        if not self.is_market_status_closed:
514            for ob in self.orderbooks:
515                list_of_pubkeys += [ob.pubkey, ob.slab_asks_pubkey, ob.slab_asks_pubkey]
516        return list_of_pubkeys
517    
518    async def get_implied_market_status(
519            self
520        ) -> MarketStatus:
521        """
522        Returns what we believe the market status ought to be (rather than what is stored in the market's state on-chain)
523
524        Note: As a fail safe, markets have specified times beyond which the market will react as if it is in another Status until it is formally cranked to that Status.
525        For example, if Solana were to have issues and it was not possible for the market's authority to crank it into In-Play status or to Cease Trading in time,
526        the market would use the System Time as a trigger to treat new requests as if it were in the later Status.
527
528        If Solana clock time is beyond TradingCeaseTime, market is TradingCeased
529        If Solana clock time is beyond InPlayStartTime but before TradingCeaseTime, market is ActiveInPlay
530
531        Returns:
532            MarketStatus: Implied market status
533        """
534        solana_datetime = await self.aver_client.get_system_clock_datetime()
535        if solana_datetime.timestamp() > self.market_state.trading_cease_time:
536            return MarketStatus.TRADING_CEASED
537        if self.market_state.inplay_start_time is not None and solana_datetime.timestamp() > self.market_state.inplay_start_time :
538            return MarketStatus.ACTIVE_IN_PLAY
539        return self.market_state.market_status
540
541    async def crank_market(
542            self,
543            outcome_idxs: list[int] = None,
544            reward_target: PublicKey = None,
545            payer: Keypair = None,
546        ):
547        """
548        Refresh market before cranking
549        If no outcome_idx are passed, all outcomes are cranked if they meet the criteria to be cranked.
550        """
551        if outcome_idxs == None:
552            # For binary markets, there is only one orderbook
553            outcome_idxs = [idx for idx in range(
554                1 if self.market_state.number_of_outcomes == 2 else self.market_state.number_of_outcomes)]
555        if self.market_state.number_of_outcomes == 2 and (0 in outcome_idxs or 1 in outcome_idxs):
556            outcome_idxs = [0]
557        if reward_target == None:
558            reward_target = self.aver_client.owner.public_key
559        if payer == None:
560            payer = self.aver_client.owner
561
562        # refreshed_market = await refresh_market(self.aver_client, self)
563
564        event_queues = [o.event_queue for o in self.market_store_state.orderbook_accounts]
565        loaded_event_queues = await load_all_event_queues(
566            self.aver_client.provider.connection,
567            event_queues 
568            )
569
570        sig = ''
571        for idx in outcome_idxs:
572            if loaded_event_queues[idx]["header"].count == 0:
573                continue
574
575            print(f'Cranking market {str(self.market_pubkey)} for outcome {idx} - {loaded_event_queues[idx]["header"].count} events left to crank')
576            if loaded_event_queues[idx]['header'].count > 0:
577                user_accounts = []
578                for j, event in enumerate(loaded_event_queues[idx]['nodes']):
579                    if type(event) == Fill:
580                        user_accounts += [event.maker_user_market]
581                    else:  # Out
582                        user_accounts += [event.user_market]
583                    if j == MAX_ITERATIONS_FOR_CONSUME_EVENTS:
584                        break
585                user_accounts = prepare_user_accounts_list(user_accounts)
586                events_to_crank = min(
587                    loaded_event_queues[idx]['header'].count, MAX_ITERATIONS_FOR_CONSUME_EVENTS)
588
589                sig = await self.consume_events(
590                    outcome_idx=idx,
591                    max_iterations=events_to_crank,
592                    user_accounts=user_accounts,
593                    reward_target=reward_target,
594                    payer=payer,
595                )
596
597        return sig
598
599    async def consume_events(
600        self,
601        outcome_idx: int,
602        user_accounts: list[PublicKey],
603        max_iterations: int = None,
604        reward_target: PublicKey = None,
605        payer: Keypair = None,
606    ):
607        """
608        Consume events
609
610        Sends instructions on chain
611
612        Args:
613            outcome_idx (int): index of the outcome
614            user_accounts (list[PublicKey]): List of User Account public keys
615            max_iterations (int, optional): Depth of events to iterate through. Defaults to MAX_ITERATIONS_FOR_CONSUME_EVENTS.
616            reward_target (PublicKey, optional): Target for reward. Defaults to AverClient wallet.
617            payer (Keypair, optional): Fee payer. Defaults to AverClient wallet.
618
619        Returns:
620            Transaction Signature: TransactionSignature object
621        """
622        if reward_target == None:
623            reward_target = self.aver_client.owner.public_key
624        if payer == None:
625            payer = self.aver_client.owner
626        if max_iterations > MAX_ITERATIONS_FOR_CONSUME_EVENTS or max_iterations == None:
627            max_iterations = MAX_ITERATIONS_FOR_CONSUME_EVENTS
628        
629        user_accounts_unsorted = [AccountMeta(
630                pk, False, True) for pk in user_accounts]
631                
632        remaining_accounts = sorted(user_accounts_unsorted, key=lambda account: bytes(account.pubkey))
633
634        return await self.aver_client.program.rpc["consume_events"](
635                max_iterations,
636                outcome_idx,
637                ctx=Context(
638                    accounts={
639                        "market": self.market_pubkey,
640                        "market_store": self.market_state.market_store,
641                        "orderbook": self.market_store_state.orderbook_accounts[outcome_idx].orderbook,
642                        "event_queue": self.market_store_state.orderbook_accounts[outcome_idx].event_queue,
643                        "reward_target": reward_target,
644                    },
645                    remaining_accounts=remaining_accounts,
646                ),
647            )

AverMarket object

Contains information, references and and orderbooks on a particular market

AverMarket( aver_client: pyaver.aver_client.AverClient, market_pubkey: solana.publickey.PublicKey, market_state: pyaver.data_classes.MarketState, market_store_state: pyaver.data_classes.MarketStoreState = None, orderbooks: list[pyaver.orderbook.Orderbook] = None)
44    def __init__(
45        self, 
46        aver_client: AverClient, 
47        market_pubkey: PublicKey,
48        market_state: MarketState,
49        market_store_state: MarketStoreState = None,
50        orderbooks: list[Orderbook] = None,
51        ):
52        """
53        Initialise an AverMarket object. Do not use this function; use AverMarket.load() instead.
54
55        Args:
56            aver_client (AverClient): AverClient object
57            market_pubkey (PublicKey): Market public key
58            market_state (MarketState): MarketState object
59            market_store_state (MarketStoreState, optional): MarketStoreState object. Defaults to None.
60            orderbooks (list[Orderbook], optional): List of Orderbook objects. Defaults to None.
61        """
62        self.market_pubkey = market_pubkey
63        self.market_state = market_state
64        self.market_store_state = market_store_state
65        self.orderbooks = orderbooks
66        self.aver_client = aver_client
67
68        if(market_state.number_of_outcomes == 2 and orderbooks is not None and len(orderbooks) == 1):
69            orderbooks.append(orderbooks[0].invert())

Initialise an AverMarket object. Do not use this function; use AverMarket.load() instead.

Args
  • aver_client (AverClient): AverClient object
  • market_pubkey (PublicKey): Market public key
  • market_state (MarketState): MarketState object
  • market_store_state (MarketStoreState, optional): MarketStoreState object. Defaults to None.
  • orderbooks (list[Orderbook], optional): List of Orderbook objects. Defaults to None.
market_pubkey: solana.publickey.PublicKey

Market pubkey

MarketState object holding data about the market

MarketStoreStateobject holding data about the market required during active trading.

This does not exist if the market has stopped trading, voided or resolved

orderbooks: list[pyaver.orderbook.Orderbook]

Ordered list of Orderbooks for this market.

Note: Binary (two-outcome0) markets only have 1 orderbook.

AverClient object

@staticmethod
async def load( aver_client: pyaver.aver_client.AverClient, market_pubkey: solana.publickey.PublicKey)
71    @staticmethod
72    async def load(aver_client: AverClient, market_pubkey: PublicKey):
73        """
74        Initialises an AverMarket object
75
76        To refresh data on an already loaded market use src.refresh.refresh_markets()
77
78        Args:
79            aver_client (AverClient): AverClient object
80            market_pubkey (PublicKey): Market public key
81
82        Returns:
83            AverMarket: AverMarket object
84        """
85        market_state_and_store = await AverMarket.load_market_state_and_store(aver_client, market_pubkey)
86        market_state: MarketState = market_state_and_store['market_states'][0]
87        market_store_state = None
88        orderbooks = None
89        is_market_status_closed = AverMarket.is_market_status_closed(market_state.market_status)
90        market_store_state: MarketStoreState = market_state_and_store['market_stores'][0]
91
92        if(not is_market_status_closed):
93            orderbooks = await AverMarket.get_orderbooks_from_orderbook_accounts(
94                aver_client.provider.connection,
95                market_store_state.orderbook_accounts,
96                [market_state.decimals] * len(market_store_state.orderbook_accounts)
97            )
98
99        return AverMarket(aver_client, market_pubkey, market_state, market_store_state, orderbooks)

Initialises an AverMarket object

To refresh data on an already loaded market use src.refresh.refresh_markets()

Args
  • aver_client (AverClient): AverClient object
  • market_pubkey (PublicKey): Market public key
Returns

AverMarket: AverMarket object

@staticmethod
async def load_multiple( aver_client: pyaver.aver_client.AverClient, market_pubkeys: list[solana.publickey.PublicKey])
101    @staticmethod
102    async def load_multiple(aver_client: AverClient, market_pubkeys: list[PublicKey]):
103        """
104        Initialises multiple AverMarket objects
105
106        This method is quicker that using Market.load() multiple times
107
108        To refresh data on already loaded markets use src.refresh.refresh_multiple_markets()
109
110        Args:
111            aver_client (AverClient): AverClient object
112            market_pubkeys (list[PublicKey]): List of Market public keys
113
114        Returns:
115            list[AverMarket]: List of AverMarket objects
116        """
117        market_states_and_stores = await AverMarket.load_multiple_market_states_and_stores(aver_client, market_pubkeys)
118        market_states: list[MarketState] = market_states_and_stores['market_states']
119
120        are_market_statuses_closed = []
121        for market_state in market_states:
122            are_market_statuses_closed.append(AverMarket.is_market_status_closed(market_state.market_status))
123
124        market_stores: list[MarketStoreState] = market_states_and_stores['market_stores']
125
126        orderbooks_market_list = await AverMarket.get_orderbooks_from_orderbook_accounts_multiple_markets(
127            aver_client.provider.connection,
128            market_states,
129            market_stores,
130            are_market_statuses_closed,
131        )
132        
133        markets: list[AverMarket] = []
134        for index, market_pubkey in enumerate(market_pubkeys):
135            market = AverMarket(
136                aver_client, 
137                market_pubkey,
138                market_states[index], 
139                market_stores[index], 
140                orderbooks_market_list[index]
141                )
142            markets.append(market)
143        
144        return markets

Initialises multiple AverMarket objects

This method is quicker that using Market.load() multiple times

To refresh data on already loaded markets use src.refresh.refresh_multiple_markets()

Args
  • aver_client (AverClient): AverClient object
  • market_pubkeys (list[PublicKey]): List of Market public keys
Returns

list[AverMarket]: List of AverMarket objects

@staticmethod
async def load_market_state( aver_client: pyaver.aver_client.AverClient, market_pubkey: solana.publickey.PublicKey) -> pyaver.data_classes.MarketState:
146    @staticmethod
147    async def load_market_state(aver_client: AverClient, market_pubkey: PublicKey) -> MarketState:
148        """
149        Loads onchain data for a MarketState
150
151        Args:
152            aver_client (AverClient): AverClient object
153            market_pubkey (PublicKey): Market public key
154
155        Returns:
156            MarketState: MarketState object
157        """
158        res = await aver_client.program.account['Market'].fetch(market_pubkey)
159        return res

Loads onchain data for a MarketState

Args
  • aver_client (AverClient): AverClient object
  • market_pubkey (PublicKey): Market public key
Returns

MarketState: MarketState object

@staticmethod
async def load_multiple_market_states( aver_client: pyaver.aver_client.AverClient, market_pubkeys: list[solana.publickey.PublicKey]) -> list[pyaver.data_classes.MarketState]:
161    @staticmethod
162    async def load_multiple_market_states(aver_client: AverClient, market_pubkeys: list[PublicKey]) -> list[MarketState]:
163        """
164        Loads onchain data for multiple MarketStates
165
166        Args:
167            aver_client (AverClient): AverClient object
168            market_pubkeys (list[PublicKey]): List of market public keys
169
170        Returns:
171            list[MarketState]: List of MarketState objects
172        """
173        res = await aver_client.program.account['Market'].fetch_multiple(market_pubkeys)
174        return res

Loads onchain data for multiple MarketStates

Args
  • aver_client (AverClient): AverClient object
  • market_pubkeys (list[PublicKey]): List of market public keys
Returns

list[MarketState]: List of MarketState objects

@staticmethod
async def load_market_state_and_store( aver_client: pyaver.aver_client.AverClient, market_pubkey: solana.publickey.PublicKey)
176    @staticmethod
177    async def load_market_state_and_store(aver_client: AverClient, market_pubkey: PublicKey):
178        """
179        Loads onchain data for multiple MarketStates and MarketStoreStates at once
180
181        Args:
182            aver_client (AverClient): AverClient object
183            market_pubkey (PublicKey]: Market public key
184
185        Returns:
186            dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores
187        """
188        return await AverMarket.load_multiple_market_states_and_stores(aver_client, [market_pubkey])

Loads onchain data for multiple MarketStates and MarketStoreStates at once

Args
  • aver_client (AverClient): AverClient object
  • market_pubkey (PublicKey]: Market public key
Returns

dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores

@staticmethod
async def load_multiple_market_states_and_stores( aver_client: pyaver.aver_client.AverClient, market_pubkeys: list[solana.publickey.PublicKey])
190    @staticmethod
191    async def load_multiple_market_states_and_stores(aver_client: AverClient, market_pubkeys: list[PublicKey]):
192        """
193        Loads onchain data for multiple MarketStates and MarketStoreStates at once
194
195        Args:
196            aver_client (AverClient): AverClient object
197            market_pubkeys (list[PublicKey]): List of market public keys
198
199        Returns:
200            dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores
201        """
202        market_store_pubkeys = [AverMarket.derive_market_store_pubkey_and_bump(m, AVER_PROGRAM_ID)[0] for m in market_pubkeys]
203
204        data = await load_multiple_bytes_data(aver_client.connection, market_pubkeys + market_store_pubkeys)
205        market_states_data = data[0:len(market_pubkeys)]
206        market_stores_data = data[len(market_pubkeys):]
207
208        market_states = [parse_market_state(d, aver_client) for d in market_states_data]
209        market_stores = [parse_market_store(d, aver_client) if d is not None else None for d in market_stores_data]
210
211        return {'market_states': market_states, 'market_stores': market_stores}

Loads onchain data for multiple MarketStates and MarketStoreStates at once

Args
  • aver_client (AverClient): AverClient object
  • market_pubkeys (list[PublicKey]): List of market public keys
Returns

dict[str, list[MarketState] or list[MarketStoreState]]: Keys are market_states or market_stores

@staticmethod
def derive_market_store_pubkey_and_bump( market_pubkey: solana.publickey.PublicKey, program_id: solana.publickey.PublicKey = 6q5ZGhEj6kkmEjuyCXuH4x8493bpi9fNzvy9L8hX83HQ)
213    @staticmethod
214    def derive_market_store_pubkey_and_bump(market_pubkey: PublicKey, program_id: PublicKey = AVER_PROGRAM_ID):
215        """
216        Derives PDA (Program Derived Account) for MarketStore public key.
217        MarketStore account addresses are derived deterministically using the market's pubkey.
218
219        Args:
220            market_pubkey (PublicKey): Market public key
221            program_id (PublicKey, optional): Program public key. Defaults to AVER_PROGRAM_ID.
222
223        Returns:
224            PublicKey: MarketStore public key
225        """
226        return PublicKey.find_program_address(
227            [bytes('market-store', 'utf-8'), bytes(market_pubkey)], 
228            program_id
229        )

Derives PDA (Program Derived Account) for MarketStore public key. MarketStore account addresses are derived deterministically using the market's pubkey.

Args
  • market_pubkey (PublicKey): Market public key
  • program_id (PublicKey, optional): Program public key. Defaults to AVER_PROGRAM_ID.
Returns

PublicKey: MarketStore public key

@staticmethod
def get_markets_from_account_states( aver_client: pyaver.aver_client.AverClient, market_pubkeys: list[solana.publickey.PublicKey], market_states: list[pyaver.data_classes.MarketState], market_stores: list[pyaver.data_classes.MarketStoreState], slabs: list[pyaver.slab.Slab])
231    @staticmethod
232    def get_markets_from_account_states(
233        aver_client: AverClient,
234        market_pubkeys: list[PublicKey], 
235        market_states: list[MarketState], 
236        market_stores: list[MarketStoreState],
237        slabs: list[Slab],
238        ):
239        """
240        Returns multiple AverMarket objects from their respective MarketStates, stores and orderbook objects
241
242        Used in refresh.py
243
244        Args:
245            aver_client (AverClient): AverClient object
246            market_pubkeys (list[PublicKey]): List of market public keys
247            market_states (list[MarketState]): List of MarketState objects
248            market_stores (list[MarketStoreState]): List of MarketStoreState objects
249            slabs (list[Slab]): List of slab objects (used in orderbooks)
250
251        Returns:
252            lst[AverMarket]: List of AverMarket objects
253        """
254        slab_position_counter = 0
255        all_orderbooks = []
256        for j, market_store in enumerate(market_stores):
257            all_orderbooks_for_market = []
258            if(market_store is None):
259                all_orderbooks.append(None)
260                continue
261            for i, orderbook in enumerate(market_store.orderbook_accounts):
262                orderbook = Orderbook(
263                    orderbook.orderbook, 
264                    slabs[slab_position_counter + i * 2],
265                    slabs[slab_position_counter + i * 2 + 1],
266                    orderbook.bids,
267                    orderbook.asks,
268                    market_states[j].decimals
269                    )
270                all_orderbooks_for_market.append(orderbook)
271            slab_position_counter += len(market_store.orderbook_accounts) * 2
272            all_orderbooks.append(all_orderbooks_for_market)
273        
274        markets: list[AverMarket] = []
275        for i, m in enumerate(market_pubkeys):
276            markets.append(AverMarket(
277                aver_client, 
278                m, 
279                market_states[i],
280                market_stores[i],
281                all_orderbooks[i]
282                )
283            )
284
285        return markets

Returns multiple AverMarket objects from their respective MarketStates, stores and orderbook objects

Used in refresh.py

Args
  • aver_client (AverClient): AverClient object
  • market_pubkeys (list[PublicKey]): List of market public keys
  • market_states (list[MarketState]): List of MarketState objects
  • market_stores (list[MarketStoreState]): List of MarketStoreState objects
  • slabs (list[Slab]): List of slab objects (used in orderbooks)
Returns

lst[AverMarket]: List of AverMarket objects

@staticmethod
async def load_market_store_state( aver_client: pyaver.aver_client.AverClient, is_market_status_closed: bool, market_store_pubkey: solana.publickey.PublicKey) -> pyaver.data_classes.MarketStoreState:
288    @staticmethod
289    async def load_market_store_state(
290        aver_client: AverClient, 
291        is_market_status_closed: bool,
292        market_store_pubkey: PublicKey, 
293        ) -> MarketStoreState:
294        """
295        Loads onchain data for a MarketStore State
296
297        Args:
298            aver_client (AverClient): AverClient object
299            is_market_status_closed (bool): True if market status is closed, voided or resolved
300            market_store_pubkey (PublicKey): MarketStore public key
301
302        Returns:
303            MarketStoreState: MarketStoreStateobject
304        """
305        #Closed markets do not have orderbooks
306        if(is_market_status_closed):
307            return None
308        res = await aver_client.program.account['MarketStore'].fetch(market_store_pubkey)
309        return res

Loads onchain data for a MarketStore State

Args
  • aver_client (AverClient): AverClient object
  • is_market_status_closed (bool): True if market status is closed, voided or resolved
  • market_store_pubkey (PublicKey): MarketStore public key
Returns

MarketStoreState: MarketStoreStateobject

@staticmethod
async def load_multiple_market_store_states( aver_client: pyaver.aver_client.AverClient, market_store_pubkeys: list[solana.publickey.PublicKey]) -> list[pyaver.data_classes.MarketStoreState]:
312    @staticmethod
313    async def load_multiple_market_store_states(
314        aver_client: AverClient, 
315        market_store_pubkeys: list[PublicKey], 
316        ) -> list[MarketStoreState]:
317        """
318        Loads onchain data for multiple MarketStore States
319
320        Args:
321            aver_client (AverClient): AverClient object
322            market_store_pubkeys (list[PublicKey]): List of MarketStore public keys
323
324        Returns:
325            list[MarketStoreState]: List of MarketStore public keys
326        """
327        res = await aver_client.program.account['MarketStore'].fetch_multiple(market_store_pubkeys)
328        return res       

Loads onchain data for multiple MarketStore States

Args
  • aver_client (AverClient): AverClient object
  • market_store_pubkeys (list[PublicKey]): List of MarketStore public keys
Returns

list[MarketStoreState]: List of MarketStore public keys

@staticmethod
def is_market_status_closed(market_status: pyaver.enums.MarketStatus)
330    @staticmethod
331    def is_market_status_closed(market_status: MarketStatus):
332        """
333        Checks if a market no longer in a trading status, and therefore will have no Orderbook or MarketStore accounts.
334        Note: Once trading has ceased for a market, these accounts are closed.
335
336        Args:
337            market_status (MarketStatus): Market status (find in MarketState object)
338
339        Returns:
340            bool: Market status closed
341        """
342        return market_status in [MarketStatus.CEASED_CRANKED_CLOSED, MarketStatus.RESOLVED, MarketStatus.VOIDED]

Checks if a market no longer in a trading status, and therefore will have no Orderbook or MarketStore accounts. Note: Once trading has ceased for a market, these accounts are closed.

Args
  • market_status (MarketStatus): Market status (find in MarketState object)
Returns

bool: Market status closed

@staticmethod
async def get_orderbooks_from_orderbook_accounts( conn: solana.rpc.async_api.AsyncClient, orderbook_accounts: list[pyaver.data_classes.OrderbookAccountsState], decimals_list: list[int]) -> list[pyaver.orderbook.Orderbook]:
344    @staticmethod
345    async def get_orderbooks_from_orderbook_accounts(
346        conn: AsyncClient, 
347        orderbook_accounts: list[OrderbookAccountsState],
348        decimals_list: list[int]
349        ) -> list[Orderbook]:
350        """
351        Returns Orderbook objects from Orderbook Account objects, by fetching and parsing. 
352
353        Args:
354            conn (AsyncClient): Solana AsyncClient object
355            orderbook_accounts (list[OrderbookAccountsState]): List of orderbook account objects
356            decimals_list (list[int]): List of decimal precision for each orderbook account state. Variable normally found in MarketState object
357
358        Raises:
359            Exception: Decimals list and orderbook accounts do not have the same length
360
361        Returns:
362            list[Orderbook]: List of orderbook objects
363        """
364        if(len(decimals_list) != len(orderbook_accounts)):
365            raise Exception('decimals_list and orderbook_accounts should have the same length')
366        
367        all_bids_and_asks_accounts = []
368        for o in orderbook_accounts:
369            all_bids_and_asks_accounts.append(o.bids)
370            all_bids_and_asks_accounts.append(o.asks)
371
372        
373        all_slabs = await Orderbook.load_multiple_slabs(conn, all_bids_and_asks_accounts)
374        orderbooks = []
375
376        for i, o in enumerate(orderbook_accounts):
377            orderbook = Orderbook(
378                o.orderbook, 
379                all_slabs[i*2], 
380                all_slabs[i*2 + 1], 
381                o.bids,o.asks,
382                decimals_list[i]
383                )
384            orderbooks.append(orderbook)
385        return orderbooks

Returns Orderbook objects from Orderbook Account objects, by fetching and parsing.

Args
  • conn (AsyncClient): Solana AsyncClient object
  • orderbook_accounts (list[OrderbookAccountsState]): List of orderbook account objects
  • decimals_list (list[int]): List of decimal precision for each orderbook account state. Variable normally found in MarketState object
Raises
  • Exception: Decimals list and orderbook accounts do not have the same length
Returns

list[Orderbook]: List of orderbook objects

@staticmethod
async def get_orderbooks_from_orderbook_accounts_multiple_markets( conn: solana.rpc.async_api.AsyncClient, market_states: list[pyaver.data_classes.MarketState], market_stores: list[pyaver.data_classes.MarketStoreState], are_market_statuses_closed: list[bool])
389    @staticmethod
390    async def get_orderbooks_from_orderbook_accounts_multiple_markets(
391        conn: AsyncClient,
392        market_states: list[MarketState],
393        market_stores: list[MarketStoreState],
394        are_market_statuses_closed: list[bool],
395    ):
396        """
397        Returns Orderbook objects from MarketState and MarketStoreStateobjects,
398        by fetching and parsing for multiple markets.
399
400        Use when fetching orderbooks for multiple markets 
401
402        Args:
403            conn (AsyncClient): Solana AsyncClient object
404            market_states (list[MarketState]): List of MarketState objects
405            market_stores (list[MarketStoreState]): List of MarketStoreStateobjects
406            are_market_statuses_closed (list[bool]): Lists if each market is closed or not
407
408        Returns:
409            list[list[Orderbook]]: List of orderbooks for each market
410        """
411        #Create list of accounts and the decimals for each account
412        orderbook_accounts = []
413        decimals_list = []
414        for index, market_store in enumerate(market_stores):
415            if(market_store is None):
416                continue
417            orderbook_accounts.extend(market_store.orderbook_accounts)
418            for i in range(len(market_store.orderbook_accounts)):
419                decimals_list.append(market_states[index].decimals)
420        
421        #Load all orderbooks
422        all_orderbooks: list[Orderbook] = await AverMarket.get_orderbooks_from_orderbook_accounts(conn, orderbook_accounts, decimals_list)
423        orderbooks_market_list = []
424
425        #Create a list for each market we received. The list contains all orderbooks for that market
426        for index, market_state in enumerate(market_states):
427            number_of_outcomes = market_state.number_of_outcomes
428            orderbooks = []
429            #Market is closed
430            if(are_market_statuses_closed[index]):
431                orderbooks_market_list.append(None)
432                continue
433            #Binary markets only have 1 orderbook
434            if(number_of_outcomes == 2):
435                orderbooks.append(all_orderbooks.pop(0))
436            else:
437                orderbooks = []
438                for i in range(number_of_outcomes):
439                    orderbooks.append(all_orderbooks.pop(0))
440            orderbooks_market_list.append(orderbooks)
441        
442        return orderbooks_market_list

Returns Orderbook objects from MarketState and MarketStoreStateobjects, by fetching and parsing for multiple markets.

Use when fetching orderbooks for multiple markets

Args
  • conn (AsyncClient): Solana AsyncClient object
  • market_states (list[MarketState]): List of MarketState objects
  • market_stores (list[MarketStoreState]): List of MarketStoreStateobjects
  • are_market_statuses_closed (list[bool]): Lists if each market is closed or not
Returns

list[list[Orderbook]]: List of orderbooks for each market

def make_sweep_fees_instruction(self)
445    def make_sweep_fees_instruction(self):
446        """
447        Creates instruction to sweeps fees and sends to relevant accounts
448
449        Returns TransactionInstruction object only. Does not send transaction.
450
451        Returns:
452            TransactionInstruction: TransactionInstruction object
453        """
454        quote_token = self.aver_client.quote_token
455        third_party_vault_authority, bump = PublicKey.find_program_address(
456            [b"third-party-token-vault", bytes(quote_token)], AVER_PROGRAM_ID)
457
458        third_party_vault_token_account = get_associated_token_address(
459            third_party_vault_authority, quote_token)
460
461        aver_quote_token_account = get_associated_token_address(
462            AVER_MARKET_AUTHORITY, quote_token
463        )
464
465        return self.aver_client.program.instruction["sweep_fees"](
466            ctx=Context(
467                accounts={
468                    "market": self.market_pubkey,
469                    "quote_vault": self.market_state.quote_vault,
470                    "vault_authority": self.market_state.vault_authority,
471                    "third_party_token_vault": third_party_vault_token_account,
472                    "aver_quote_token_account": aver_quote_token_account,
473                    "spl_token_program": TOKEN_PROGRAM_ID,
474                },
475                signers=[],
476            ),
477        )

Creates instruction to sweeps fees and sends to relevant accounts

Returns TransactionInstruction object only. Does not send transaction.

Returns

TransactionInstruction: TransactionInstruction object

async def sweep_fees( self, fee_payer: solana.keypair.Keypair = None, send_options: solana.rpc.types.TxOpts = None)
479    async def sweep_fees(self, fee_payer: Keypair = None, send_options: TxOpts = None,):
480        """
481        Sweeps fees and sends to relevant accounts
482
483        Sends instructions on chain
484
485        Args:
486            fee_payer (Keypair): Pays transaction fees. Defaults to AverClient wallet
487            send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
488
489        Returns:
490            RPCResponse: Response
491        """
492        if(fee_payer == None):
493            fee_payer = self.aver_client.owner
494
495        ix = self.make_sweep_fees_instruction()
496
497        return await sign_and_send_transaction_instructions(
498            self.aver_client,
499            [],
500            fee_payer,
501            [ix],
502            send_options
503        )

Sweeps fees and sends to relevant accounts

Sends instructions on chain

Args
  • fee_payer (Keypair): Pays transaction fees. Defaults to AverClient wallet
  • send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
Returns

RPCResponse: Response

def list_all_pubkeys(self)
505    def list_all_pubkeys(self):
506        """
507        Returns all pubkeys used in AverMarket object
508
509        Returns:
510            list[PublicKey]: List of public keys
511        """
512        list_of_pubkeys = [self.market_pubkey, self.market_state.quote_vault, self.market_state.oracle_feed]
513        if not self.is_market_status_closed:
514            for ob in self.orderbooks:
515                list_of_pubkeys += [ob.pubkey, ob.slab_asks_pubkey, ob.slab_asks_pubkey]
516        return list_of_pubkeys

Returns all pubkeys used in AverMarket object

Returns

list[PublicKey]: List of public keys

async def get_implied_market_status(self) -> pyaver.enums.MarketStatus:
518    async def get_implied_market_status(
519            self
520        ) -> MarketStatus:
521        """
522        Returns what we believe the market status ought to be (rather than what is stored in the market's state on-chain)
523
524        Note: As a fail safe, markets have specified times beyond which the market will react as if it is in another Status until it is formally cranked to that Status.
525        For example, if Solana were to have issues and it was not possible for the market's authority to crank it into In-Play status or to Cease Trading in time,
526        the market would use the System Time as a trigger to treat new requests as if it were in the later Status.
527
528        If Solana clock time is beyond TradingCeaseTime, market is TradingCeased
529        If Solana clock time is beyond InPlayStartTime but before TradingCeaseTime, market is ActiveInPlay
530
531        Returns:
532            MarketStatus: Implied market status
533        """
534        solana_datetime = await self.aver_client.get_system_clock_datetime()
535        if solana_datetime.timestamp() > self.market_state.trading_cease_time:
536            return MarketStatus.TRADING_CEASED
537        if self.market_state.inplay_start_time is not None and solana_datetime.timestamp() > self.market_state.inplay_start_time :
538            return MarketStatus.ACTIVE_IN_PLAY
539        return self.market_state.market_status

Returns what we believe the market status ought to be (rather than what is stored in the market's state on-chain)

Note: As a fail safe, markets have specified times beyond which the market will react as if it is in another Status until it is formally cranked to that Status. For example, if Solana were to have issues and it was not possible for the market's authority to crank it into In-Play status or to Cease Trading in time, the market would use the System Time as a trigger to treat new requests as if it were in the later Status.

If Solana clock time is beyond TradingCeaseTime, market is TradingCeased If Solana clock time is beyond InPlayStartTime but before TradingCeaseTime, market is ActiveInPlay

Returns

MarketStatus: Implied market status

async def crank_market( self, outcome_idxs: list[int] = None, reward_target: solana.publickey.PublicKey = None, payer: solana.keypair.Keypair = None)
541    async def crank_market(
542            self,
543            outcome_idxs: list[int] = None,
544            reward_target: PublicKey = None,
545            payer: Keypair = None,
546        ):
547        """
548        Refresh market before cranking
549        If no outcome_idx are passed, all outcomes are cranked if they meet the criteria to be cranked.
550        """
551        if outcome_idxs == None:
552            # For binary markets, there is only one orderbook
553            outcome_idxs = [idx for idx in range(
554                1 if self.market_state.number_of_outcomes == 2 else self.market_state.number_of_outcomes)]
555        if self.market_state.number_of_outcomes == 2 and (0 in outcome_idxs or 1 in outcome_idxs):
556            outcome_idxs = [0]
557        if reward_target == None:
558            reward_target = self.aver_client.owner.public_key
559        if payer == None:
560            payer = self.aver_client.owner
561
562        # refreshed_market = await refresh_market(self.aver_client, self)
563
564        event_queues = [o.event_queue for o in self.market_store_state.orderbook_accounts]
565        loaded_event_queues = await load_all_event_queues(
566            self.aver_client.provider.connection,
567            event_queues 
568            )
569
570        sig = ''
571        for idx in outcome_idxs:
572            if loaded_event_queues[idx]["header"].count == 0:
573                continue
574
575            print(f'Cranking market {str(self.market_pubkey)} for outcome {idx} - {loaded_event_queues[idx]["header"].count} events left to crank')
576            if loaded_event_queues[idx]['header'].count > 0:
577                user_accounts = []
578                for j, event in enumerate(loaded_event_queues[idx]['nodes']):
579                    if type(event) == Fill:
580                        user_accounts += [event.maker_user_market]
581                    else:  # Out
582                        user_accounts += [event.user_market]
583                    if j == MAX_ITERATIONS_FOR_CONSUME_EVENTS:
584                        break
585                user_accounts = prepare_user_accounts_list(user_accounts)
586                events_to_crank = min(
587                    loaded_event_queues[idx]['header'].count, MAX_ITERATIONS_FOR_CONSUME_EVENTS)
588
589                sig = await self.consume_events(
590                    outcome_idx=idx,
591                    max_iterations=events_to_crank,
592                    user_accounts=user_accounts,
593                    reward_target=reward_target,
594                    payer=payer,
595                )
596
597        return sig

Refresh market before cranking If no outcome_idx are passed, all outcomes are cranked if they meet the criteria to be cranked.

async def consume_events( self, outcome_idx: int, user_accounts: list[solana.publickey.PublicKey], max_iterations: int = None, reward_target: solana.publickey.PublicKey = None, payer: solana.keypair.Keypair = None)
599    async def consume_events(
600        self,
601        outcome_idx: int,
602        user_accounts: list[PublicKey],
603        max_iterations: int = None,
604        reward_target: PublicKey = None,
605        payer: Keypair = None,
606    ):
607        """
608        Consume events
609
610        Sends instructions on chain
611
612        Args:
613            outcome_idx (int): index of the outcome
614            user_accounts (list[PublicKey]): List of User Account public keys
615            max_iterations (int, optional): Depth of events to iterate through. Defaults to MAX_ITERATIONS_FOR_CONSUME_EVENTS.
616            reward_target (PublicKey, optional): Target for reward. Defaults to AverClient wallet.
617            payer (Keypair, optional): Fee payer. Defaults to AverClient wallet.
618
619        Returns:
620            Transaction Signature: TransactionSignature object
621        """
622        if reward_target == None:
623            reward_target = self.aver_client.owner.public_key
624        if payer == None:
625            payer = self.aver_client.owner
626        if max_iterations > MAX_ITERATIONS_FOR_CONSUME_EVENTS or max_iterations == None:
627            max_iterations = MAX_ITERATIONS_FOR_CONSUME_EVENTS
628        
629        user_accounts_unsorted = [AccountMeta(
630                pk, False, True) for pk in user_accounts]
631                
632        remaining_accounts = sorted(user_accounts_unsorted, key=lambda account: bytes(account.pubkey))
633
634        return await self.aver_client.program.rpc["consume_events"](
635                max_iterations,
636                outcome_idx,
637                ctx=Context(
638                    accounts={
639                        "market": self.market_pubkey,
640                        "market_store": self.market_state.market_store,
641                        "orderbook": self.market_store_state.orderbook_accounts[outcome_idx].orderbook,
642                        "event_queue": self.market_store_state.orderbook_accounts[outcome_idx].event_queue,
643                        "reward_target": reward_target,
644                    },
645                    remaining_accounts=remaining_accounts,
646                ),
647            )

Consume events

Sends instructions on chain

Args
  • outcome_idx (int): index of the outcome
  • user_accounts (list[PublicKey]): List of User Account public keys
  • max_iterations (int, optional): Depth of events to iterate through. Defaults to MAX_ITERATIONS_FOR_CONSUME_EVENTS.
  • reward_target (PublicKey, optional): Target for reward. Defaults to AverClient wallet.
  • payer (Keypair, optional): Fee payer. Defaults to AverClient wallet.
Returns

Transaction Signature: TransactionSignature object