update solanapy

This commit is contained in:
Ennio Nasca 2022-10-18 16:51:11 +02:00
parent 49271da70f
commit 2954a7779f
8 changed files with 1359 additions and 963 deletions

View File

@ -10,7 +10,7 @@ allow_prereleases = true
install-ci-deps = "pipenv install --dev --skip-lock black pydocstyle flake8 pylint mypy pytest"
[dev-packages]
jupyterlab = "*"
notebook = "*"
black = "*"
pytest = "*"
pylint = "*"
@ -28,7 +28,7 @@ pytest-asyncio = "*"
types-requests = "*"
[packages]
solana = {version = ">=0.15.0"}
solana = {version = ">=0.27.0"}
construct = "*"
flake8 = "*"
construct-typing = "*"

2040
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,9 @@ from typing import List
from solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.rpc.async_api import AsyncClient
from solana.rpc.types import RPCResponse, TxOpts
from solana.rpc.types import TxOpts
from solana.transaction import Transaction
from solders.rpc.responses import SendTransactionResp
import pyserum.market.types as t
from pyserum import instructions
@ -28,8 +29,15 @@ LAMPORTS_PER_SOL = 1000000000
class AsyncMarket(MarketCore):
"""Represents a Serum Market."""
def __init__(self, conn: AsyncClient, market_state: MarketState, force_use_request_queue: bool = False) -> None:
super().__init__(market_state=market_state, force_use_request_queue=force_use_request_queue)
def __init__(
self,
conn: AsyncClient,
market_state: MarketState,
force_use_request_queue: bool = False,
) -> None:
super().__init__(
market_state=market_state, force_use_request_queue=force_use_request_queue
)
self._conn = conn
@classmethod
@ -50,7 +58,9 @@ class AsyncMarket(MarketCore):
market_state = await MarketState.async_load(conn, market_address, program_id)
return cls(conn, market_state, force_use_request_queue)
async def find_open_orders_accounts_for_owner(self, owner_address: PublicKey) -> List[AsyncOpenOrdersAccount]:
async def find_open_orders_accounts_for_owner(
self, owner_address: PublicKey
) -> List[AsyncOpenOrdersAccount]:
return await AsyncOpenOrdersAccount.find_for_market_and_owner(
self._conn, self.state.public_key(), owner_address, self.state.program_id()
)
@ -69,7 +79,9 @@ class AsyncMarket(MarketCore):
"""Load orders for owner."""
bids = await self.load_bids()
asks = await self.load_asks()
open_orders_accounts = await self.find_open_orders_accounts_for_owner(owner_address)
open_orders_accounts = await self.find_open_orders_accounts_for_owner(
owner_address
)
return self._parse_orders_for_owner(bids, asks, open_orders_accounts)
async def load_event_queue(self) -> List[t.Event]:
@ -98,16 +110,23 @@ class AsyncMarket(MarketCore):
max_quantity: float,
client_id: int = 0,
opts: TxOpts = TxOpts(),
) -> RPCResponse: # TODO: Add open_orders_address_key param and fee_discount_pubkey
) -> SendTransactionResp: # TODO: Add open_orders_address_key param and fee_discount_pubkey
transaction = Transaction()
signers: List[Keypair] = [owner]
open_order_accounts = await self.find_open_orders_accounts_for_owner(owner.public_key)
open_order_accounts = await self.find_open_orders_accounts_for_owner(
owner.public_key
)
if open_order_accounts:
place_order_open_order_account = open_order_accounts[0].address
else:
mbfre_resp = await self._conn.get_minimum_balance_for_rent_exemption(OPEN_ORDERS_LAYOUT.sizeof())
mbfre_resp = await self._conn.get_minimum_balance_for_rent_exemption(
OPEN_ORDERS_LAYOUT.sizeof()
)
place_order_open_order_account = self._after_oo_mbfre_resp(
mbfre_resp=mbfre_resp, owner=owner, signers=signers, transaction=transaction
mbfre_resp=mbfre_resp,
owner=owner,
signers=signers,
transaction=transaction,
)
# TODO: Cache new_open_orders_account
# TODO: Handle fee_discount_pubkey
@ -128,18 +147,26 @@ class AsyncMarket(MarketCore):
return await self._conn.send_transaction(transaction, *signers, opts=opts)
async def cancel_order_by_client_id(
self, owner: Keypair, open_orders_account: PublicKey, client_id: int, opts: TxOpts = TxOpts()
) -> RPCResponse:
self,
owner: Keypair,
open_orders_account: PublicKey,
client_id: int,
opts: TxOpts = TxOpts(),
) -> SendTransactionResp:
txs = self._build_cancel_order_by_client_id_tx(
owner=owner, open_orders_account=open_orders_account, client_id=client_id
)
return await self._conn.send_transaction(txs, owner, opts=opts)
async def cancel_order(self, owner: Keypair, order: t.Order, opts: TxOpts = TxOpts()) -> RPCResponse:
async def cancel_order(
self, owner: Keypair, order: t.Order, opts: TxOpts = TxOpts()
) -> SendTransactionResp:
txn = self._build_cancel_order_tx(owner=owner, order=order)
return await self._conn.send_transaction(txn, owner, opts=opts)
async def match_orders(self, fee_payer: Keypair, limit: int, opts: TxOpts = TxOpts()) -> RPCResponse:
async def match_orders(
self, fee_payer: Keypair, limit: int, opts: TxOpts = TxOpts()
) -> SendTransactionResp:
txn = self._build_match_orders_tx(limit)
return await self._conn.send_transaction(txn, fee_payer, opts=opts)
@ -150,12 +177,12 @@ class AsyncMarket(MarketCore):
base_wallet: PublicKey,
quote_wallet: PublicKey, # TODO: add referrer_quote_wallet.
opts: TxOpts = TxOpts(),
) -> RPCResponse:
) -> SendTransactionResp:
# TODO: Handle wrapped sol accounts
should_wrap_sol = self._settle_funds_should_wrap_sol()
if should_wrap_sol:
mbfre_resp = await self._conn.get_minimum_balance_for_rent_exemption(165)
min_bal_for_rent_exemption = mbfre_resp["result"]
min_bal_for_rent_exemption = mbfre_resp.value
else:
min_bal_for_rent_exemption = 0 # value only matters if should_wrap_sol
signers = [owner]

View File

@ -7,11 +7,16 @@ from typing import List, Union
from solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.rpc.types import RPCResponse
from solana.system_program import CreateAccountParams, create_account
from solana.transaction import Transaction, TransactionInstruction
from solders.rpc.responses import GetMinimumBalanceForRentExemptionResp
from spl.token.constants import ACCOUNT_LEN, TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT
from spl.token.instructions import CloseAccountParams, InitializeAccountParams, close_account, initialize_account
from spl.token.instructions import (
CloseAccountParams,
InitializeAccountParams,
close_account,
initialize_account,
)
import pyserum.market.types as t
from pyserum import instructions
@ -32,20 +37,25 @@ class MarketCore:
logger = logging.getLogger("pyserum.market.Market")
def __init__(self, market_state: MarketState, force_use_request_queue: bool = False) -> None:
def __init__(
self, market_state: MarketState, force_use_request_queue: bool = False
) -> None:
self.state = market_state
self.force_use_request_queue = force_use_request_queue
def _use_request_queue(self) -> bool:
return (
# DEX Version 1
self.state.program_id == PublicKey("4ckmDgGdxQoPDLUkDT3vHgSAkzA3QRdNq5ywwY4sUSJn")
self.state.program_id
== PublicKey("4ckmDgGdxQoPDLUkDT3vHgSAkzA3QRdNq5ywwY4sUSJn")
or
# DEX Version 1
self.state.program_id == PublicKey("BJ3jrUzddfuSrZHXSCxMUUQsjKEyLmuuyZebkcaFp2fg")
self.state.program_id
== PublicKey("BJ3jrUzddfuSrZHXSCxMUUQsjKEyLmuuyZebkcaFp2fg")
or
# DEX Version 2
self.state.program_id == PublicKey("EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o")
self.state.program_id
== PublicKey("EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o")
or self.force_use_request_queue
)
@ -58,7 +68,9 @@ class MarketCore:
def find_best_fee_discount_key(self, owner: PublicKey, cache_duration: int):
raise NotImplementedError("find_best_fee_discount_key not implemented")
def find_quote_token_accounts_for_owner(self, owner_address: PublicKey, include_unwrapped_sol: bool = False):
def find_quote_token_accounts_for_owner(
self, owner_address: PublicKey, include_unwrapped_sol: bool = False
):
raise NotImplementedError("find_quote_token_accounts_for_owner not implemented")
def _parse_bids_or_asks(self, bytes_data: bytes) -> OrderBook:
@ -71,7 +83,9 @@ class MarketCore:
all_orders = itertools.chain(bids.orders(), asks.orders())
open_orders_addresses = {str(o.address) for o in open_orders_accounts}
orders = [o for o in all_orders if str(o.open_order_address) in open_orders_addresses]
orders = [
o for o in all_orders if str(o.open_order_address) in open_orders_addresses
]
return orders
def load_base_token_for_owner(self):
@ -110,11 +124,16 @@ class MarketCore:
side=side,
price=price,
size=size,
fee_cost=event.native_fee_or_rebate * (1 if event.event_flags.maker else -1),
fee_cost=event.native_fee_or_rebate
* (1 if event.event_flags.maker else -1),
)
def _prepare_new_oo_account(
self, owner: Keypair, balance_needed: int, signers: List[Keypair], transaction: Transaction
self,
owner: Keypair,
balance_needed: int,
signers: List[Keypair],
transaction: Transaction,
) -> PublicKey:
# new_open_orders_account = Account()
new_open_orders_account = Keypair()
@ -141,7 +160,9 @@ class MarketCore:
limit_price: float,
max_quantity: float,
client_id: int,
open_order_accounts: Union[List[OpenOrdersAccount], List[AsyncOpenOrdersAccount]],
open_order_accounts: Union[
List[OpenOrdersAccount], List[AsyncOpenOrdersAccount]
],
place_order_open_order_account: PublicKey,
) -> None:
# unwrapped SOL cannot be used for payment
@ -149,9 +170,9 @@ class MarketCore:
raise ValueError("Invalid payer account. Cannot use unwrapped SOL.")
# TODO: add integration test for SOL wrapping.
should_wrap_sol = (side == Side.BUY and self.state.quote_mint() == WRAPPED_SOL_MINT) or (
side == Side.SELL and self.state.base_mint() == WRAPPED_SOL_MINT
)
should_wrap_sol = (
side == Side.BUY and self.state.quote_mint() == WRAPPED_SOL_MINT
) or (side == Side.SELL and self.state.base_mint() == WRAPPED_SOL_MINT)
if should_wrap_sol:
# wrapped_sol_account = Account()
@ -208,10 +229,16 @@ class MarketCore:
)
def _after_oo_mbfre_resp(
self, mbfre_resp: RPCResponse, owner: Keypair, signers: List[Keypair], transaction: Transaction
self,
mbfre_resp: GetMinimumBalanceForRentExemptionResp,
owner: Keypair,
signers: List[Keypair],
transaction: Transaction,
) -> PublicKey:
balance_needed = mbfre_resp["result"]
place_order_open_order_account = self._prepare_new_oo_account(owner, balance_needed, signers, transaction)
balance_needed = mbfre_resp.value
place_order_open_order_account = self._prepare_new_oo_account(
owner, balance_needed, signers, transaction
)
return place_order_open_order_account
@staticmethod
@ -219,7 +246,9 @@ class MarketCore:
price: float,
size: float,
side: Side,
open_orders_accounts: Union[List[OpenOrdersAccount], List[AsyncOpenOrdersAccount]],
open_orders_accounts: Union[
List[OpenOrdersAccount], List[AsyncOpenOrdersAccount]
],
) -> int:
lamports = 0
if side == Side.BUY:
@ -246,9 +275,9 @@ class MarketCore:
fee_discount_pubkey: PublicKey = None,
) -> TransactionInstruction:
if self.state.base_size_number_to_lots(max_quantity) < 0:
raise Exception("Size lot %d is too small" % max_quantity)
raise Exception(f"Size lot %d is too small {max_quantity}")
if self.state.price_number_to_lots(limit_price) < 0:
raise Exception("Price lot %d is too small" % limit_price)
raise Exception(f"Price lot %d is too small {limit_price}")
if self._use_request_queue():
return instructions.new_order(
instructions.NewOrderParams(
@ -297,7 +326,11 @@ class MarketCore:
def _build_cancel_order_by_client_id_tx(
self, owner: Keypair, open_orders_account: PublicKey, client_id: int
) -> Transaction:
return Transaction().add(self.make_cancel_order_by_client_id_instruction(owner, open_orders_account, client_id))
return Transaction().add(
self.make_cancel_order_by_client_id_instruction(
owner, open_orders_account, client_id
)
)
def make_cancel_order_by_client_id_instruction(
self, owner: Keypair, open_orders_account: PublicKey, client_id: int
@ -327,9 +360,13 @@ class MarketCore:
)
def _build_cancel_order_tx(self, owner: Keypair, order: t.Order) -> Transaction:
return Transaction().add(self.make_cancel_order_instruction(owner.public_key, order))
return Transaction().add(
self.make_cancel_order_instruction(owner.public_key, order)
)
def make_cancel_order_instruction(self, owner: PublicKey, order: t.Order) -> TransactionInstruction:
def make_cancel_order_instruction(
self, owner: PublicKey, order: t.Order
) -> TransactionInstruction:
if self._use_request_queue():
return instructions.cancel_order(
instructions.CancelOrderParams(
@ -389,7 +426,10 @@ class MarketCore:
if open_orders.owner != owner.public_key:
raise Exception("Invalid open orders account")
vault_signer = PublicKey.create_program_address(
[bytes(self.state.public_key()), self.state.vault_signer_nonce().to_bytes(8, byteorder="little")],
[
bytes(self.state.public_key()),
self.state.vault_signer_nonce().to_bytes(8, byteorder="little"),
],
self.state.program_id(),
)
transaction = Transaction()
@ -425,8 +465,12 @@ class MarketCore:
transaction.add(
self.make_settle_funds_instruction(
open_orders,
base_wallet if self.state.base_mint() != WRAPPED_SOL_MINT else wrapped_sol_account.public_key,
quote_wallet if self.state.quote_mint() != WRAPPED_SOL_MINT else wrapped_sol_account.public_key,
base_wallet
if self.state.base_mint() != WRAPPED_SOL_MINT
else wrapped_sol_account.public_key,
quote_wallet
if self.state.quote_mint() != WRAPPED_SOL_MINT
else wrapped_sol_account.public_key,
vault_signer,
)
)
@ -446,7 +490,9 @@ class MarketCore:
return transaction
def _settle_funds_should_wrap_sol(self) -> bool:
return (self.state.quote_mint() == WRAPPED_SOL_MINT) or (self.state.base_mint() == WRAPPED_SOL_MINT)
return (self.state.quote_mint() == WRAPPED_SOL_MINT) or (
self.state.base_mint() == WRAPPED_SOL_MINT
)
def make_settle_funds_instruction(
self,

View File

@ -6,8 +6,9 @@ from typing import List
from solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.rpc.api import Client
from solana.rpc.types import RPCResponse, TxOpts
from solana.rpc.types import TxOpts
from solana.transaction import Transaction
from solders.rpc.responses import SendTransactionResp
import pyserum.market.types as t
from pyserum import instructions
@ -28,8 +29,15 @@ LAMPORTS_PER_SOL = 1000000000
class Market(MarketCore):
"""Represents a Serum Market."""
def __init__(self, conn: Client, market_state: MarketState, force_use_request_queue: bool = False) -> None:
super().__init__(market_state=market_state, force_use_request_queue=force_use_request_queue)
def __init__(
self,
conn: Client,
market_state: MarketState,
force_use_request_queue: bool = False,
) -> None:
super().__init__(
market_state=market_state, force_use_request_queue=force_use_request_queue
)
self._conn = conn
@classmethod
@ -50,7 +58,9 @@ class Market(MarketCore):
market_state = MarketState.load(conn, market_address, program_id)
return cls(conn, market_state, force_use_request_queue)
def find_open_orders_accounts_for_owner(self, owner_address: PublicKey) -> List[OpenOrdersAccount]:
def find_open_orders_accounts_for_owner(
self, owner_address: PublicKey
) -> List[OpenOrdersAccount]:
return OpenOrdersAccount.find_for_market_and_owner(
self._conn, self.state.public_key(), owner_address, self.state.program_id()
)
@ -98,16 +108,21 @@ class Market(MarketCore):
max_quantity: float,
client_id: int = 0,
opts: TxOpts = TxOpts(),
) -> RPCResponse: # TODO: Add open_orders_address_key param and fee_discount_pubkey
) -> SendTransactionResp: # TODO: Add open_orders_address_key param and fee_discount_pubkey
transaction = Transaction()
signers: List[Keypair] = [owner]
open_order_accounts = self.find_open_orders_accounts_for_owner(owner.public_key)
if open_order_accounts:
place_order_open_order_account = open_order_accounts[0].address
else:
mbfre_resp = self._conn.get_minimum_balance_for_rent_exemption(OPEN_ORDERS_LAYOUT.sizeof())
mbfre_resp = self._conn.get_minimum_balance_for_rent_exemption(
OPEN_ORDERS_LAYOUT.sizeof()
)
place_order_open_order_account = self._after_oo_mbfre_resp(
mbfre_resp=mbfre_resp, owner=owner, signers=signers, transaction=transaction
mbfre_resp=mbfre_resp,
owner=owner,
signers=signers,
transaction=transaction,
)
# TODO: Cache new_open_orders_account
# TODO: Handle fee_discount_pubkey
@ -128,18 +143,26 @@ class Market(MarketCore):
return self._conn.send_transaction(transaction, *signers, opts=opts)
def cancel_order_by_client_id(
self, owner: Keypair, open_orders_account: PublicKey, client_id: int, opts: TxOpts = TxOpts()
) -> RPCResponse:
self,
owner: Keypair,
open_orders_account: PublicKey,
client_id: int,
opts: TxOpts = TxOpts(),
) -> SendTransactionResp:
txs = self._build_cancel_order_by_client_id_tx(
owner=owner, open_orders_account=open_orders_account, client_id=client_id
)
return self._conn.send_transaction(txs, owner, opts=opts)
def cancel_order(self, owner: Keypair, order: t.Order, opts: TxOpts = TxOpts()) -> RPCResponse:
def cancel_order(
self, owner: Keypair, order: t.Order, opts: TxOpts = TxOpts()
) -> SendTransactionResp:
txn = self._build_cancel_order_tx(owner=owner, order=order)
return self._conn.send_transaction(txn, owner, opts=opts)
def match_orders(self, fee_payer: Keypair, limit: int, opts: TxOpts = TxOpts()) -> RPCResponse:
def match_orders(
self, fee_payer: Keypair, limit: int, opts: TxOpts = TxOpts()
) -> SendTransactionResp:
txn = self._build_match_orders_tx(limit)
return self._conn.send_transaction(txn, fee_payer, opts=opts)
@ -150,11 +173,13 @@ class Market(MarketCore):
base_wallet: PublicKey,
quote_wallet: PublicKey, # TODO: add referrer_quote_wallet.
opts: TxOpts = TxOpts(),
) -> RPCResponse:
) -> SendTransactionResp:
# TODO: Handle wrapped sol accounts
should_wrap_sol = self._settle_funds_should_wrap_sol()
min_bal_for_rent_exemption = (
self._conn.get_minimum_balance_for_rent_exemption(165)["result"] if should_wrap_sol else 0
self._conn.get_minimum_balance_for_rent_exemption(165).value
if should_wrap_sol
else 0
) # value only matters if should_wrap_sol
signers = [owner]
transaction = self._build_settle_funds_tx(

View File

@ -126,10 +126,10 @@ class MarketState: # pylint: disable=too-many-public-methods
return self._quote_mint_decimals
def base_spl_token_multiplier(self) -> int:
return 10 ** self._base_mint_decimals
return 10**self._base_mint_decimals
def quote_spl_token_multiplier(self) -> int:
return 10 ** self._quote_mint_decimals
return 10**self._quote_mint_decimals
def base_spl_size_to_number(self, size: int) -> float:
return size / self.base_spl_token_multiplier()

View File

@ -1,14 +1,14 @@
from __future__ import annotations
import base64
from typing import List, NamedTuple, Tuple, Type, TypeVar
from solana.publickey import PublicKey
from solana.rpc.api import Client
from solana.rpc.commitment import Recent
from solana.rpc.types import Commitment, MemcmpOpts, RPCResponse
from solana.rpc.types import Commitment, MemcmpOpts
from solana.system_program import CreateAccountParams, create_account
from solana.transaction import TransactionInstruction
from solders.rpc.responses import GetProgramAccountsResp
from ._layouts.open_orders import OPEN_ORDERS_LAYOUT
from .instructions import DEFAULT_DEX_PROGRAM_ID
@ -57,7 +57,10 @@ class _OpenOrdersAccountCore: # pylint: disable=too-many-instance-attributes,to
@classmethod
def from_bytes(cls: Type[_T], address: PublicKey, buffer: bytes) -> _T:
open_order_decoded = OPEN_ORDERS_LAYOUT.parse(buffer)
if not open_order_decoded.account_flags.open_orders or not open_order_decoded.account_flags.initialized:
if (
not open_order_decoded.account_flags.open_orders
or not open_order_decoded.account_flags.initialized
):
raise Exception("Not an open order account or not initialized.")
return cls(
@ -70,38 +73,49 @@ class _OpenOrdersAccountCore: # pylint: disable=too-many-instance-attributes,to
quote_token_total=open_order_decoded.quote_token_total,
free_slot_bits=int.from_bytes(open_order_decoded.free_slot_bits, "little"),
is_bid_bits=int.from_bytes(open_order_decoded.is_bid_bits, "little"),
orders=[int.from_bytes(order, "little") for order in open_order_decoded.orders],
orders=[
int.from_bytes(order, "little") for order in open_order_decoded.orders
],
client_ids=open_order_decoded.client_ids,
)
@classmethod
def _process_get_program_accounts_resp(cls: Type[_T], resp: RPCResponse) -> List[_T]:
def _process_get_program_accounts_resp(
cls: Type[_T], resp: GetProgramAccountsResp
) -> List[_T]:
accounts = []
for account in resp["result"]:
account_details = account["account"]
for keyed_account in resp.value:
account_details = keyed_account.account
accounts.append(
ProgramAccount(
public_key=PublicKey(account["pubkey"]),
data=base64.decodebytes(account_details["data"][0].encode("ascii")),
is_executablable=bool(account_details["executable"]),
owner=PublicKey(account_details["owner"]),
lamports=int(account_details["lamports"]),
public_key=PublicKey(keyed_account.pubkey),
data=account_details.data,
is_executablable=account_details.executable,
owner=PublicKey(account_details.owner),
lamports=account_details.lamports,
)
)
return [cls.from_bytes(account.public_key, account.data) for account in accounts]
return [
cls.from_bytes(account.public_key, account.data) for account in accounts
]
@staticmethod
def _build_get_program_accounts_args(
market: PublicKey, program_id: PublicKey, owner: PublicKey, commitment: Commitment
) -> Tuple[PublicKey, Commitment, str, None, int, List[MemcmpOpts]]:
market: PublicKey,
program_id: PublicKey,
owner: PublicKey,
commitment: Commitment,
) -> Tuple[PublicKey, Commitment, str, None, List[MemcmpOpts]]:
filters = [
MemcmpOpts(
offset=5 + 8, # 5 bytes of padding, 8 bytes of account flag
bytes=str(market),
),
MemcmpOpts(
offset=5 + 8 + 32, # 5 bytes of padding, 8 bytes of account flag, 32 bytes of market public key
offset=5
+ 8
+ 32, # 5 bytes of padding, 8 bytes of account flag, 32 bytes of market public key
bytes=str(owner),
),
]
@ -111,7 +125,6 @@ class _OpenOrdersAccountCore: # pylint: disable=too-many-instance-attributes,to
commitment,
"base64",
data_slice,
OPEN_ORDERS_LAYOUT.sizeof(),
filters,
)
@ -119,7 +132,12 @@ class _OpenOrdersAccountCore: # pylint: disable=too-many-instance-attributes,to
class OpenOrdersAccount(_OpenOrdersAccountCore):
@classmethod
def find_for_market_and_owner( # pylint: disable=too-many-arguments
cls, conn: Client, market: PublicKey, owner: PublicKey, program_id: PublicKey, commitment: Commitment = Recent
cls,
conn: Client,
market: PublicKey,
owner: PublicKey,
program_id: PublicKey,
commitment: Commitment = Recent,
) -> List[OpenOrdersAccount]:
args = cls._build_get_program_accounts_args(
market=market, program_id=program_id, owner=owner, commitment=commitment

View File

@ -1,18 +1,16 @@
import base64
from solana.publickey import PublicKey
from solana.rpc.api import Client
from solana.rpc.types import RPCResponse
from solders.account import Account
from solders.rpc.responses import GetAccountInfoResp
from spl.token.constants import WRAPPED_SOL_MINT
from pyserum._layouts.market import MINT_LAYOUT
def parse_bytes_data(res: RPCResponse) -> bytes:
if ("result" not in res) or ("value" not in res["result"]) or ("data" not in res["result"]["value"]):
def parse_bytes_data(res: GetAccountInfoResp) -> bytes:
if not isinstance(res.value, Account):
raise Exception("Cannot load byte data.")
data = res["result"]["value"]["data"][0]
return base64.decodebytes(data.encode("ascii"))
return res.value.data
def load_bytes_data(addr: PublicKey, conn: Client) -> bytes: