pyaver.utils

  1from .aver_client import AverClient
  2from spl.token.instructions import get_associated_token_address
  3from spl.token._layouts import ACCOUNT_LAYOUT
  4from spl.token.constants import ACCOUNT_LEN
  5from .data_classes import UserBalanceState, MarketStatus
  6from solana.publickey import PublicKey
  7from .errors import parse_error
  8from .slab import Slab
  9from solana.keypair import Keypair
 10from solana.rpc.types import RPCResponse, TxOpts
 11import base64
 12from anchorpy.error import ProgramError
 13from solana.publickey import PublicKey
 14from solana.rpc.async_api import AsyncClient
 15from solana.transaction import TransactionInstruction, Transaction
 16
 17def parse_bytes_data(res: RPCResponse) -> bytes:
 18    """
 19    Parses bytes from an RPC response
 20
 21    Args:
 22        res (RPCResponse): Response
 23
 24    Raises:
 25        Exception: Cannot load byte data
 26
 27    Returns:
 28        bytes: Parsed data
 29    """
 30    if ("result" not in res) or ("value" not in res["result"]) or ("data" not in res["result"]["value"]):
 31        raise Exception(f"Cannot load byte data. {res['error']}")
 32    data = res["result"]["value"]["data"][0]
 33    return base64.decodebytes(data.encode("ascii"))
 34
 35def parse_multiple_bytes_data(res: RPCResponse, is_only_getting_data: bool = True) -> list[bytes]:
 36    """
 37    Parses bytes from an RPC response for multiple accounts
 38
 39    Args:
 40        res (RPCResponse): Response
 41        is_only_getting_data (bool, optional): Only returns account data if true; gets all information otherwise. Defaults to True.
 42
 43    Raises:
 44        Exception: Cannot load byte data
 45
 46    Returns:
 47        list[bytes]: List of parsed byte data
 48    """
 49    if ("result" not in res) or ("value" not in res["result"]):
 50        raise Exception(f"Cannot load byte data. {res['error']}")
 51    data_list = []
 52    raw_data_list = res['result']['value']
 53    for r in raw_data_list:
 54        if(r is None):
 55            data_list.append(None)
 56            continue
 57        if(is_only_getting_data):
 58            data_list.append(base64.decodebytes(r['data'][0].encode('ascii')))
 59        else:
 60            datum = r
 61            datum['data'] = base64.decodebytes(r['data'][0].encode('ascii'))
 62            data_list.append(datum)
 63    return data_list
 64
 65async def load_bytes_data(conn: AsyncClient, address: PublicKey) -> bytes:
 66    """
 67    Fetch account data from AsyncClient 
 68
 69    Args:
 70        conn (AsyncClient): Solana AsyncClient object
 71        address (PublicKey): Public key of account to be loaded
 72
 73    Returns:
 74        bytes: bytes
 75    """
 76    res = await conn.get_account_info(address)
 77    return parse_bytes_data(res)
 78
 79#This function chunks requests into max size of 100 accounts
 80async def load_multiple_bytes_data(
 81    conn: AsyncClient, 
 82    addresses_remaining: list[PublicKey], 
 83    loaded_data_so_far: list[bytes] = [],
 84    is_only_getting_data: bool = True):
 85    """
 86    Fetch account data from AsyncClient for multiple accounts
 87
 88    Args:
 89        conn (AsyncClient): Solana AsyncClient object
 90        addresses_remaining (list[PublicKey]): Public keys of accounts to be loaded
 91        loaded_data_so_far (list[bytes], optional): Parameter for recursive use of function. Defaults to [].
 92        is_only_getting_data (bool, optional): Only returns account data if true; gets all information otherwise. Defaults to True.
 93
 94    Returns:
 95        list[bytes]: _description_
 96    """
 97    if(len(addresses_remaining) == 0):
 98        return loaded_data_so_far
 99    
100    addresses_to_load = addresses_remaining[:100]
101    res = await conn.get_multiple_accounts(addresses_to_load)
102    return await load_multiple_bytes_data(
103        conn,
104        addresses_remaining[100:],
105        loaded_data_so_far + parse_multiple_bytes_data(res, is_only_getting_data),
106        is_only_getting_data
107    )
108
109#TODO - calculate lamports required for transaction    
110async def sign_and_send_transaction_instructions(
111    client: AverClient,
112    signers: list[Keypair],
113    fee_payer: Keypair,
114    tx_instructions: list[TransactionInstruction],
115    send_options: TxOpts = None,
116    manual_max_retry: int = 0
117):
118    """
119    Cryptographically signs transaction and sends onchain
120
121    Args:
122        client (AverClient): AverClient object
123        signers (list[Keypair]): List of signing keypairs
124        fee_payer (Keypair): Keypair to pay fee for transaction
125        tx_instructions (list[TransactionInstruction]): List of transaction instructions to pack into transaction to be sent
126        send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
127
128    Raises:
129        error: COMING SOON
130
131    Returns:
132        RPCResponse: Response
133    """
134    tx = Transaction()
135    if(not fee_payer in signers):
136        signers = [fee_payer] + signers
137    tx.add(*tx_instructions)
138    if(send_options == None):
139        send_options = client.provider.opts
140    
141
142    attempts = 0
143    while attempts <= manual_max_retry:
144        try:
145            return await client.provider.connection.send_transaction(tx, *signers, opts=send_options)
146        except Exception as e:
147            error = parse_error(e, client.program)
148            if(isinstance(error, ProgramError)):
149                raise error
150            else:
151                attempts = attempts + 1
152                
153
154
155def calculate_tick_size_for_price(limit_price: float):
156    """
157    Calculates tick size for specific price
158
159    Args:
160        limit_price (float): Limit price
161
162    Raises:
163        Exception: Limit price too low
164        Exception: Limit price too high
165
166    Returns:
167        int: Tick size
168    """
169    if(limit_price < 1_000):
170        raise Exception('Limit price too low')
171    if(limit_price <= 2_000):
172        return 100
173    if(limit_price <= 5_000):
174        return 250
175    if(limit_price <= 10_000):
176        return 500
177    if(limit_price <= 20_000):
178        return 1_000
179    if(limit_price <= 50_000):
180        return 2_500
181    if(limit_price <= 100_000):
182        return 5_000
183    if(limit_price <= 990_000):
184        return 10_000
185    if(limit_price > 990_000):
186        raise Exception('Limit price too high')
187    return limit_price
188
189def round_price_to_nearest_tick_size(limit_price: float):
190    """
191    Rounds price to the nearest tick size available
192
193    Args:
194        limit_price (float): Limit price
195
196    Returns:
197        float: Rounded limit price
198    """
199    limit_price_to_6dp = limit_price * (10 ** 6)
200    tick_size  = calculate_tick_size_for_price(limit_price_to_6dp)
201    rounded_limit_price_to_6dp = round(limit_price_to_6dp/tick_size) * tick_size
202    rounded_limit_price = rounded_limit_price_to_6dp / (10 ** 6)
203
204    return rounded_limit_price
205
206def parse_user_market_state(buffer: bytes, aver_client: AverClient):
207        """
208        Parses raw onchain data to UserMarketState object        
209        Args:
210            buffer (bytes): Raw bytes coming from onchain
211            aver_client (AverClient): AverClient object
212
213        Returns:
214            UserMarket: UserMarketState object
215        """
216        #uma_parsed = USER_MARKET_STATE_LAYOUT.parse(buffer)
217        uma_parsed = aver_client.program.account['UserMarket'].coder.accounts.decode(buffer)
218        return uma_parsed
219
220def parse_market_state(buffer: bytes, aver_client: AverClient):
221        """
222        Parses raw onchain data to MarketState object        
223        Args:
224            buffer (bytes): Raw bytes coming from onchain
225            aver_client (AverClient): AverClient object
226
227        Returns:
228            MarketState: MarketState object
229        """
230        
231        market_account_info = aver_client.program.account['Market'].coder.accounts.decode(buffer)
232        return market_account_info
233
234def parse_market_store(buffer: bytes, aver_client: AverClient):
235        """
236        Parses onchain data for a MarketStore State
237
238        Args:
239            buffer (bytes): Raw bytes coming from onchain
240            aver_client (AverClient): AverClient
241
242        Returns:
243            MarketStore: MarketStore object
244        """
245        market_store_account_info = aver_client.program.account['MarketStore'].coder.accounts.decode(buffer)
246        return market_store_account_info  
247
248
249def parse_user_host_lifetime_state(aver_client: AverClient, buffer):
250        """
251        Parses raw onchain data to UserHostLifetime object
252
253        Args:
254            aver_client (AverClient): AverClient object
255            buffer (bytes): Raw bytes coming from onchain
256
257        Returns:
258            UserHostLifetime: UserHostLifetime object
259        """
260        user_host_lifetime_info = aver_client.program.account['UserHostLifetime'].coder.accounts.decode(buffer)
261        return user_host_lifetime_info
262
263async def load_multiple_account_states(
264        aver_client: AverClient,
265        market_pubkeys: list[PublicKey],
266        market_store_pubkeys: list[PublicKey],
267        slab_pubkeys: list[PublicKey],
268        user_market_pubkeys: list[PublicKey] = [],
269        user_pubkeys: list[PublicKey] = [],
270        uhl_pubkeys: list[PublicKey] = []
271    ):
272        """
273        Fetchs account data for multiple account types at once
274
275        Used in refresh.py to quckly and efficiently pull all account data at once
276
277        Args:
278            aver_client (AverClient): AverClient object
279            market_pubkeys (list[PublicKey]): List of MarketState object public keys
280            market_store_pubkeys (list[PublicKey]): List of MarketStoreStore object public keys
281            slab_pubkeys (list[PublicKey]): List of Slab public keys for orderbooks
282            user_market_pubkeys (list[PublicKey], optional): List of UserMarketState object public keys. Defaults to [].
283            user_pubkeys (list[PublicKey], optional): List of UserMarket owners' public keys. Defaults to [].
284            uhl_pubkeuys(list[PublicKey], optional): List of UserHostLifetime public keys. Defaults to []
285
286        Returns:
287            dict[str, list]: Dictionary containing `market_states`, `market_stores`, `slabs`, `user_market_states`, `user_balance_sheets`
288        """
289        all_ata_pubkeys = [get_associated_token_address(u, aver_client.quote_token) for u in user_pubkeys]
290
291        all_pubkeys = market_pubkeys + market_store_pubkeys + slab_pubkeys + user_market_pubkeys + user_pubkeys + all_ata_pubkeys + uhl_pubkeys
292        data = await load_multiple_bytes_data(aver_client.provider.connection, all_pubkeys, [], False)
293
294        deserialized_market_state = []
295        for index, m in enumerate(market_pubkeys):
296            buffer = data[index]
297            deserialized_market_state.append(parse_market_state(buffer['data'], aver_client))
298        
299        deserialized_market_store = []
300        for index, m in enumerate(market_pubkeys):
301            buffer = data[index + len(market_pubkeys)]
302            if(buffer is None):
303                deserialized_market_store.append(None)
304                continue
305            deserialized_market_store.append(parse_market_store(buffer['data'], aver_client))
306
307        deserialized_slab_data = []
308        for index, s in enumerate(slab_pubkeys):
309            buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys)]
310            if(buffer is None):
311                deserialized_slab_data.append(None)
312                continue
313            deserialized_slab_data.append(Slab.from_bytes(buffer['data']))
314
315        deserialized_uma_data = []
316        if(user_market_pubkeys is not None):
317            for index, u in enumerate(user_market_pubkeys):
318                buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys)]
319                if(buffer is None):
320                    deserialized_uma_data.append(None)
321                    continue
322                deserialized_uma_data.append(parse_user_market_state(buffer['data'], aver_client))
323
324        lamport_balances = []
325        if(user_pubkeys is not None):
326            for index, pubkey in enumerate(user_pubkeys):
327                balance = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys) + len(user_market_pubkeys)]
328                lamport_balances.append(balance['lamports'] if balance and balance['lamports'] is not None else 0)
329
330        token_balances = []
331        if(all_ata_pubkeys is not None):
332            for index, pubkey in enumerate(all_ata_pubkeys):
333                buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys) + len(user_market_pubkeys) + len(user_pubkeys)]
334                if(len(buffer['data']) == ACCOUNT_LEN):
335                    token_balances.append(ACCOUNT_LAYOUT.parse(buffer['data'])['amount'])
336                else:
337                    token_balances.append(0)
338
339        user_balance_states = []
340        for index, x in enumerate(lamport_balances):
341            user_balance_state = UserBalanceState(lamport_balances[index], token_balances[index])
342            user_balance_states.append(user_balance_state)
343
344        uhl_states = []
345        for index, pubkey in enumerate(uhl_pubkeys):
346            buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys) + len(user_market_pubkeys) + len(user_pubkeys) + len(all_ata_pubkeys)]
347            if(buffer is None):
348                uhl_states.append(None)
349                continue
350            uhl_state = parse_user_host_lifetime_state(aver_client, buffer['data'])
351            uhl_states.append(uhl_state)
352
353        return {
354            'market_states': deserialized_market_state,
355            'market_stores': deserialized_market_store,
356            'slabs': deserialized_slab_data,
357            'user_market_states': deserialized_uma_data,
358            'user_balance_states': user_balance_states,
359            'user_host_lifetime_states': uhl_states
360        }
361
362def is_market_tradeable(market_status: MarketStatus):
363    """
364    Returns if it is possible to place an order on a market
365
366    Args:
367        market_status (MarketStatus): Market Status (found in MarketState)
368
369    Returns:
370        bool: Trade possible is true
371    """
372    return market_status in [MarketStatus.ACTIVE_IN_PLAY, MarketStatus.ACTIVE_PRE_EVENT]
373
374def can_cancel_order_in_market(market_status: MarketStatus):
375    """
376    Returns if it is possible to cancel an order on a market
377
378    Args:
379        market_status (MarketStatus): Market Status (found in MarketState)
380
381    Returns:
382        _type_: Order cancellable if true
383    """
384    return market_status in [
385        MarketStatus.ACTIVE_PRE_EVENT,
386        MarketStatus.ACTIVE_IN_PLAY,
387        MarketStatus.HALTED_IN_PLAY,
388        MarketStatus.HALTED_PRE_EVENT
389    ]
def parse_bytes_data(res: solana.rpc.types.RPCResponse) -> bytes:
18def parse_bytes_data(res: RPCResponse) -> bytes:
19    """
20    Parses bytes from an RPC response
21
22    Args:
23        res (RPCResponse): Response
24
25    Raises:
26        Exception: Cannot load byte data
27
28    Returns:
29        bytes: Parsed data
30    """
31    if ("result" not in res) or ("value" not in res["result"]) or ("data" not in res["result"]["value"]):
32        raise Exception(f"Cannot load byte data. {res['error']}")
33    data = res["result"]["value"]["data"][0]
34    return base64.decodebytes(data.encode("ascii"))

Parses bytes from an RPC response

Args
  • res (RPCResponse): Response
Raises
  • Exception: Cannot load byte data
Returns

bytes: Parsed data

def parse_multiple_bytes_data( res: solana.rpc.types.RPCResponse, is_only_getting_data: bool = True) -> list[bytes]:
36def parse_multiple_bytes_data(res: RPCResponse, is_only_getting_data: bool = True) -> list[bytes]:
37    """
38    Parses bytes from an RPC response for multiple accounts
39
40    Args:
41        res (RPCResponse): Response
42        is_only_getting_data (bool, optional): Only returns account data if true; gets all information otherwise. Defaults to True.
43
44    Raises:
45        Exception: Cannot load byte data
46
47    Returns:
48        list[bytes]: List of parsed byte data
49    """
50    if ("result" not in res) or ("value" not in res["result"]):
51        raise Exception(f"Cannot load byte data. {res['error']}")
52    data_list = []
53    raw_data_list = res['result']['value']
54    for r in raw_data_list:
55        if(r is None):
56            data_list.append(None)
57            continue
58        if(is_only_getting_data):
59            data_list.append(base64.decodebytes(r['data'][0].encode('ascii')))
60        else:
61            datum = r
62            datum['data'] = base64.decodebytes(r['data'][0].encode('ascii'))
63            data_list.append(datum)
64    return data_list

Parses bytes from an RPC response for multiple accounts

Args
  • res (RPCResponse): Response
  • is_only_getting_data (bool, optional): Only returns account data if true; gets all information otherwise. Defaults to True.
Raises
  • Exception: Cannot load byte data
Returns

list[bytes]: List of parsed byte data

async def load_bytes_data( conn: solana.rpc.async_api.AsyncClient, address: solana.publickey.PublicKey) -> bytes:
66async def load_bytes_data(conn: AsyncClient, address: PublicKey) -> bytes:
67    """
68    Fetch account data from AsyncClient 
69
70    Args:
71        conn (AsyncClient): Solana AsyncClient object
72        address (PublicKey): Public key of account to be loaded
73
74    Returns:
75        bytes: bytes
76    """
77    res = await conn.get_account_info(address)
78    return parse_bytes_data(res)

Fetch account data from AsyncClient

Args
  • conn (AsyncClient): Solana AsyncClient object
  • address (PublicKey): Public key of account to be loaded
Returns

bytes: bytes

async def load_multiple_bytes_data( conn: solana.rpc.async_api.AsyncClient, addresses_remaining: list[solana.publickey.PublicKey], loaded_data_so_far: list[bytes] = [], is_only_getting_data: bool = True)
 81async def load_multiple_bytes_data(
 82    conn: AsyncClient, 
 83    addresses_remaining: list[PublicKey], 
 84    loaded_data_so_far: list[bytes] = [],
 85    is_only_getting_data: bool = True):
 86    """
 87    Fetch account data from AsyncClient for multiple accounts
 88
 89    Args:
 90        conn (AsyncClient): Solana AsyncClient object
 91        addresses_remaining (list[PublicKey]): Public keys of accounts to be loaded
 92        loaded_data_so_far (list[bytes], optional): Parameter for recursive use of function. Defaults to [].
 93        is_only_getting_data (bool, optional): Only returns account data if true; gets all information otherwise. Defaults to True.
 94
 95    Returns:
 96        list[bytes]: _description_
 97    """
 98    if(len(addresses_remaining) == 0):
 99        return loaded_data_so_far
100    
101    addresses_to_load = addresses_remaining[:100]
102    res = await conn.get_multiple_accounts(addresses_to_load)
103    return await load_multiple_bytes_data(
104        conn,
105        addresses_remaining[100:],
106        loaded_data_so_far + parse_multiple_bytes_data(res, is_only_getting_data),
107        is_only_getting_data
108    )

Fetch account data from AsyncClient for multiple accounts

Args
  • conn (AsyncClient): Solana AsyncClient object
  • addresses_remaining (list[PublicKey]): Public keys of accounts to be loaded
  • loaded_data_so_far (list[bytes], optional): Parameter for recursive use of function. Defaults to [].
  • is_only_getting_data (bool, optional): Only returns account data if true; gets all information otherwise. Defaults to True.
Returns

list[bytes]: _description_

async def sign_and_send_transaction_instructions( client: pyaver.aver_client.AverClient, signers: list[solana.keypair.Keypair], fee_payer: solana.keypair.Keypair, tx_instructions: list[solana.transaction.TransactionInstruction], send_options: solana.rpc.types.TxOpts = None, manual_max_retry: int = 0)
111async def sign_and_send_transaction_instructions(
112    client: AverClient,
113    signers: list[Keypair],
114    fee_payer: Keypair,
115    tx_instructions: list[TransactionInstruction],
116    send_options: TxOpts = None,
117    manual_max_retry: int = 0
118):
119    """
120    Cryptographically signs transaction and sends onchain
121
122    Args:
123        client (AverClient): AverClient object
124        signers (list[Keypair]): List of signing keypairs
125        fee_payer (Keypair): Keypair to pay fee for transaction
126        tx_instructions (list[TransactionInstruction]): List of transaction instructions to pack into transaction to be sent
127        send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
128
129    Raises:
130        error: COMING SOON
131
132    Returns:
133        RPCResponse: Response
134    """
135    tx = Transaction()
136    if(not fee_payer in signers):
137        signers = [fee_payer] + signers
138    tx.add(*tx_instructions)
139    if(send_options == None):
140        send_options = client.provider.opts
141    
142
143    attempts = 0
144    while attempts <= manual_max_retry:
145        try:
146            return await client.provider.connection.send_transaction(tx, *signers, opts=send_options)
147        except Exception as e:
148            error = parse_error(e, client.program)
149            if(isinstance(error, ProgramError)):
150                raise error
151            else:
152                attempts = attempts + 1

Cryptographically signs transaction and sends onchain

Args
  • client (AverClient): AverClient object
  • signers (list[Keypair]): List of signing keypairs
  • fee_payer (Keypair): Keypair to pay fee for transaction
  • tx_instructions (list[TransactionInstruction]): List of transaction instructions to pack into transaction to be sent
  • send_options (TxOpts, optional): Options to specify when broadcasting a transaction. Defaults to None.
Raises
  • error: COMING SOON
Returns

RPCResponse: Response

def calculate_tick_size_for_price(limit_price: float)
156def calculate_tick_size_for_price(limit_price: float):
157    """
158    Calculates tick size for specific price
159
160    Args:
161        limit_price (float): Limit price
162
163    Raises:
164        Exception: Limit price too low
165        Exception: Limit price too high
166
167    Returns:
168        int: Tick size
169    """
170    if(limit_price < 1_000):
171        raise Exception('Limit price too low')
172    if(limit_price <= 2_000):
173        return 100
174    if(limit_price <= 5_000):
175        return 250
176    if(limit_price <= 10_000):
177        return 500
178    if(limit_price <= 20_000):
179        return 1_000
180    if(limit_price <= 50_000):
181        return 2_500
182    if(limit_price <= 100_000):
183        return 5_000
184    if(limit_price <= 990_000):
185        return 10_000
186    if(limit_price > 990_000):
187        raise Exception('Limit price too high')
188    return limit_price

Calculates tick size for specific price

Args
  • limit_price (float): Limit price
Raises
  • Exception: Limit price too low
  • Exception: Limit price too high
Returns

int: Tick size

def round_price_to_nearest_tick_size(limit_price: float)
190def round_price_to_nearest_tick_size(limit_price: float):
191    """
192    Rounds price to the nearest tick size available
193
194    Args:
195        limit_price (float): Limit price
196
197    Returns:
198        float: Rounded limit price
199    """
200    limit_price_to_6dp = limit_price * (10 ** 6)
201    tick_size  = calculate_tick_size_for_price(limit_price_to_6dp)
202    rounded_limit_price_to_6dp = round(limit_price_to_6dp/tick_size) * tick_size
203    rounded_limit_price = rounded_limit_price_to_6dp / (10 ** 6)
204
205    return rounded_limit_price

Rounds price to the nearest tick size available

Args
  • limit_price (float): Limit price
Returns

float: Rounded limit price

def parse_user_market_state(buffer: bytes, aver_client: pyaver.aver_client.AverClient)
207def parse_user_market_state(buffer: bytes, aver_client: AverClient):
208        """
209        Parses raw onchain data to UserMarketState object        
210        Args:
211            buffer (bytes): Raw bytes coming from onchain
212            aver_client (AverClient): AverClient object
213
214        Returns:
215            UserMarket: UserMarketState object
216        """
217        #uma_parsed = USER_MARKET_STATE_LAYOUT.parse(buffer)
218        uma_parsed = aver_client.program.account['UserMarket'].coder.accounts.decode(buffer)
219        return uma_parsed

Parses raw onchain data to UserMarketState object

Args
  • buffer (bytes): Raw bytes coming from onchain
  • aver_client (AverClient): AverClient object
Returns

UserMarket: UserMarketState object

def parse_market_state(buffer: bytes, aver_client: pyaver.aver_client.AverClient)
221def parse_market_state(buffer: bytes, aver_client: AverClient):
222        """
223        Parses raw onchain data to MarketState object        
224        Args:
225            buffer (bytes): Raw bytes coming from onchain
226            aver_client (AverClient): AverClient object
227
228        Returns:
229            MarketState: MarketState object
230        """
231        
232        market_account_info = aver_client.program.account['Market'].coder.accounts.decode(buffer)
233        return market_account_info

Parses raw onchain data to MarketState object

Args
  • buffer (bytes): Raw bytes coming from onchain
  • aver_client (AverClient): AverClient object
Returns

MarketState: MarketState object

def parse_market_store(buffer: bytes, aver_client: pyaver.aver_client.AverClient)
235def parse_market_store(buffer: bytes, aver_client: AverClient):
236        """
237        Parses onchain data for a MarketStore State
238
239        Args:
240            buffer (bytes): Raw bytes coming from onchain
241            aver_client (AverClient): AverClient
242
243        Returns:
244            MarketStore: MarketStore object
245        """
246        market_store_account_info = aver_client.program.account['MarketStore'].coder.accounts.decode(buffer)
247        return market_store_account_info  

Parses onchain data for a MarketStore State

Args
  • buffer (bytes): Raw bytes coming from onchain
  • aver_client (AverClient): AverClient
Returns

MarketStore: MarketStore object

def parse_user_host_lifetime_state(aver_client: pyaver.aver_client.AverClient, buffer)
250def parse_user_host_lifetime_state(aver_client: AverClient, buffer):
251        """
252        Parses raw onchain data to UserHostLifetime object
253
254        Args:
255            aver_client (AverClient): AverClient object
256            buffer (bytes): Raw bytes coming from onchain
257
258        Returns:
259            UserHostLifetime: UserHostLifetime object
260        """
261        user_host_lifetime_info = aver_client.program.account['UserHostLifetime'].coder.accounts.decode(buffer)
262        return user_host_lifetime_info

Parses raw onchain data to UserHostLifetime object

Args
  • aver_client (AverClient): AverClient object
  • buffer (bytes): Raw bytes coming from onchain
Returns

UserHostLifetime: UserHostLifetime object

async def load_multiple_account_states( aver_client: pyaver.aver_client.AverClient, market_pubkeys: list[solana.publickey.PublicKey], market_store_pubkeys: list[solana.publickey.PublicKey], slab_pubkeys: list[solana.publickey.PublicKey], user_market_pubkeys: list[solana.publickey.PublicKey] = [], user_pubkeys: list[solana.publickey.PublicKey] = [], uhl_pubkeys: list[solana.publickey.PublicKey] = [])
264async def load_multiple_account_states(
265        aver_client: AverClient,
266        market_pubkeys: list[PublicKey],
267        market_store_pubkeys: list[PublicKey],
268        slab_pubkeys: list[PublicKey],
269        user_market_pubkeys: list[PublicKey] = [],
270        user_pubkeys: list[PublicKey] = [],
271        uhl_pubkeys: list[PublicKey] = []
272    ):
273        """
274        Fetchs account data for multiple account types at once
275
276        Used in refresh.py to quckly and efficiently pull all account data at once
277
278        Args:
279            aver_client (AverClient): AverClient object
280            market_pubkeys (list[PublicKey]): List of MarketState object public keys
281            market_store_pubkeys (list[PublicKey]): List of MarketStoreStore object public keys
282            slab_pubkeys (list[PublicKey]): List of Slab public keys for orderbooks
283            user_market_pubkeys (list[PublicKey], optional): List of UserMarketState object public keys. Defaults to [].
284            user_pubkeys (list[PublicKey], optional): List of UserMarket owners' public keys. Defaults to [].
285            uhl_pubkeuys(list[PublicKey], optional): List of UserHostLifetime public keys. Defaults to []
286
287        Returns:
288            dict[str, list]: Dictionary containing `market_states`, `market_stores`, `slabs`, `user_market_states`, `user_balance_sheets`
289        """
290        all_ata_pubkeys = [get_associated_token_address(u, aver_client.quote_token) for u in user_pubkeys]
291
292        all_pubkeys = market_pubkeys + market_store_pubkeys + slab_pubkeys + user_market_pubkeys + user_pubkeys + all_ata_pubkeys + uhl_pubkeys
293        data = await load_multiple_bytes_data(aver_client.provider.connection, all_pubkeys, [], False)
294
295        deserialized_market_state = []
296        for index, m in enumerate(market_pubkeys):
297            buffer = data[index]
298            deserialized_market_state.append(parse_market_state(buffer['data'], aver_client))
299        
300        deserialized_market_store = []
301        for index, m in enumerate(market_pubkeys):
302            buffer = data[index + len(market_pubkeys)]
303            if(buffer is None):
304                deserialized_market_store.append(None)
305                continue
306            deserialized_market_store.append(parse_market_store(buffer['data'], aver_client))
307
308        deserialized_slab_data = []
309        for index, s in enumerate(slab_pubkeys):
310            buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys)]
311            if(buffer is None):
312                deserialized_slab_data.append(None)
313                continue
314            deserialized_slab_data.append(Slab.from_bytes(buffer['data']))
315
316        deserialized_uma_data = []
317        if(user_market_pubkeys is not None):
318            for index, u in enumerate(user_market_pubkeys):
319                buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys)]
320                if(buffer is None):
321                    deserialized_uma_data.append(None)
322                    continue
323                deserialized_uma_data.append(parse_user_market_state(buffer['data'], aver_client))
324
325        lamport_balances = []
326        if(user_pubkeys is not None):
327            for index, pubkey in enumerate(user_pubkeys):
328                balance = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys) + len(user_market_pubkeys)]
329                lamport_balances.append(balance['lamports'] if balance and balance['lamports'] is not None else 0)
330
331        token_balances = []
332        if(all_ata_pubkeys is not None):
333            for index, pubkey in enumerate(all_ata_pubkeys):
334                buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys) + len(user_market_pubkeys) + len(user_pubkeys)]
335                if(len(buffer['data']) == ACCOUNT_LEN):
336                    token_balances.append(ACCOUNT_LAYOUT.parse(buffer['data'])['amount'])
337                else:
338                    token_balances.append(0)
339
340        user_balance_states = []
341        for index, x in enumerate(lamport_balances):
342            user_balance_state = UserBalanceState(lamport_balances[index], token_balances[index])
343            user_balance_states.append(user_balance_state)
344
345        uhl_states = []
346        for index, pubkey in enumerate(uhl_pubkeys):
347            buffer = data[index + len(market_pubkeys) + len(market_store_pubkeys) + len(slab_pubkeys) + len(user_market_pubkeys) + len(user_pubkeys) + len(all_ata_pubkeys)]
348            if(buffer is None):
349                uhl_states.append(None)
350                continue
351            uhl_state = parse_user_host_lifetime_state(aver_client, buffer['data'])
352            uhl_states.append(uhl_state)
353
354        return {
355            'market_states': deserialized_market_state,
356            'market_stores': deserialized_market_store,
357            'slabs': deserialized_slab_data,
358            'user_market_states': deserialized_uma_data,
359            'user_balance_states': user_balance_states,
360            'user_host_lifetime_states': uhl_states
361        }

Fetchs account data for multiple account types at once

Used in refresh.py to quckly and efficiently pull all account data at once

Args
  • aver_client (AverClient): AverClient object
  • market_pubkeys (list[PublicKey]): List of MarketState object public keys
  • market_store_pubkeys (list[PublicKey]): List of MarketStoreStore object public keys
  • slab_pubkeys (list[PublicKey]): List of Slab public keys for orderbooks
  • user_market_pubkeys (list[PublicKey], optional): List of UserMarketState object public keys. Defaults to [].
  • user_pubkeys (list[PublicKey], optional): List of UserMarket owners' public keys. Defaults to [].
  • uhl_pubkeuys(list[PublicKey], optional): List of UserHostLifetime public keys. Defaults to []
Returns

dict[str, list]: Dictionary containing market_states, market_stores, slabs, user_market_states, user_balance_sheets

def is_market_tradeable(market_status: pyaver.enums.MarketStatus)
363def is_market_tradeable(market_status: MarketStatus):
364    """
365    Returns if it is possible to place an order on a market
366
367    Args:
368        market_status (MarketStatus): Market Status (found in MarketState)
369
370    Returns:
371        bool: Trade possible is true
372    """
373    return market_status in [MarketStatus.ACTIVE_IN_PLAY, MarketStatus.ACTIVE_PRE_EVENT]

Returns if it is possible to place an order on a market

Args
  • market_status (MarketStatus): Market Status (found in MarketState)
Returns

bool: Trade possible is true

def can_cancel_order_in_market(market_status: pyaver.enums.MarketStatus)
375def can_cancel_order_in_market(market_status: MarketStatus):
376    """
377    Returns if it is possible to cancel an order on a market
378
379    Args:
380        market_status (MarketStatus): Market Status (found in MarketState)
381
382    Returns:
383        _type_: Order cancellable if true
384    """
385    return market_status in [
386        MarketStatus.ACTIVE_PRE_EVENT,
387        MarketStatus.ACTIVE_IN_PLAY,
388        MarketStatus.HALTED_IN_PLAY,
389        MarketStatus.HALTED_PRE_EVENT
390    ]

Returns if it is possible to cancel an order on a market

Args
  • market_status (MarketStatus): Market Status (found in MarketState)
Returns

_type_: Order cancellable if true