Added support for init and close open_orders_accounts instructions (#99)

* added support for init and close open_orders_accounts instructions

* removed unused variables
This commit is contained in:
quazzuk 2021-12-23 10:16:09 +00:00 committed by GitHub
parent 6f3ba279da
commit d0938e9149
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 176 additions and 32 deletions

View File

@ -1,9 +1,9 @@
"""Layouts for dex instructions data.""" """Layouts for dex instructions data."""
from enum import IntEnum from enum import IntEnum
from construct import Switch
from construct import Bytes, Const, Int8ul, Int16ul, Int32ul, Int64ul, Pass from construct import Bytes, Const, Int8ul, Int16ul, Int32ul, Int64ul, Pass
from construct import Struct as cStruct from construct import Struct as cStruct
from construct import Switch
from .slab import KEY from .slab import KEY
@ -19,6 +19,8 @@ class InstructionType(IntEnum):
NEW_ORDER_V3 = 10 NEW_ORDER_V3 = 10
CANCEL_ORDER_V2 = 11 CANCEL_ORDER_V2 = 11
CANCEL_ORDER_BY_CLIENT_ID_V2 = 12 CANCEL_ORDER_BY_CLIENT_ID_V2 = 12
CLOSE_OPEN_ORDERS = 14
INIT_OPEN_ORDERS = 15
_VERSION = 0 _VERSION = 0
@ -70,6 +72,9 @@ _CANCEL_ORDER_V2 = cStruct(
_CANCEL_ORDER_BY_CLIENTID_V2 = cStruct("client_id" / Int64ul) _CANCEL_ORDER_BY_CLIENTID_V2 = cStruct("client_id" / Int64ul)
_CLOSE_OPEN_ORDERS = cStruct()
_INIT_OPEN_ORDERS = cStruct()
INSTRUCTIONS_LAYOUT = cStruct( INSTRUCTIONS_LAYOUT = cStruct(
"version" / Const(_VERSION, Int8ul), "version" / Const(_VERSION, Int8ul),
"instruction_type" / Int32ul, "instruction_type" / Int32ul,
@ -87,6 +92,8 @@ INSTRUCTIONS_LAYOUT = cStruct(
InstructionType.NEW_ORDER_V3: _NEW_ORDER_V3, InstructionType.NEW_ORDER_V3: _NEW_ORDER_V3,
InstructionType.CANCEL_ORDER_V2: _CANCEL_ORDER_V2, InstructionType.CANCEL_ORDER_V2: _CANCEL_ORDER_V2,
InstructionType.CANCEL_ORDER_BY_CLIENT_ID_V2: _CANCEL_ORDER_BY_CLIENTID_V2, InstructionType.CANCEL_ORDER_BY_CLIENT_ID_V2: _CANCEL_ORDER_BY_CLIENTID_V2,
InstructionType.CLOSE_OPEN_ORDERS: _CLOSE_OPEN_ORDERS,
InstructionType.INIT_OPEN_ORDERS: _INIT_OPEN_ORDERS,
}, },
), ),
) )

View File

@ -1,4 +1,5 @@
from construct import Bytes, Int64ul, Padding, Struct as cStruct from construct import Bytes, Int64ul, Padding
from construct import Struct as cStruct
from .account_flags import ACCOUNT_FLAGS_LAYOUT from .account_flags import ACCOUNT_FLAGS_LAYOUT

View File

@ -1,4 +1,4 @@
from construct import BitStruct, BitsInteger, BitsSwapped, Bytes, Const, Flag, Int8ul, Int32ul, Int64ul, Padding from construct import BitsInteger, BitsSwapped, BitStruct, Bytes, Const, Flag, Int8ul, Int32ul, Int64ul, Padding
from construct import Struct as cStruct from construct import Struct as cStruct
from .account_flags import ACCOUNT_FLAGS_LAYOUT from .account_flags import ACCOUNT_FLAGS_LAYOUT

View File

@ -3,8 +3,9 @@ from __future__ import annotations
from enum import IntEnum from enum import IntEnum
from construct import Switch, Bytes, Int8ul, Int32ul, Int64ul, Padding from construct import Bytes, Int8ul, Int32ul, Int64ul, Padding
from construct import Struct as cStruct from construct import Struct as cStruct
from construct import Switch
from .account_flags import ACCOUNT_FLAGS_LAYOUT from .account_flags import ACCOUNT_FLAGS_LAYOUT

View File

@ -1,9 +1,10 @@
from typing import List from typing import List
import httpx import httpx
from solana.rpc.async_api import AsyncClient as async_conn # pylint: disable=unused-import # noqa:F401 from solana.rpc.async_api import AsyncClient as async_conn # pylint: disable=unused-import # noqa:F401
from .market.types import MarketInfo, TokenInfo
from .connection import LIVE_MARKETS_URL, TOKEN_MINTS_URL, parse_live_markets, parse_token_mints from .connection import LIVE_MARKETS_URL, TOKEN_MINTS_URL, parse_live_markets, parse_token_mints
from .market.types import MarketInfo, TokenInfo
async def get_live_markets(httpx_client: httpx.AsyncClient) -> List[MarketInfo]: async def get_live_markets(httpx_client: httpx.AsyncClient) -> List[MarketInfo]:

View File

@ -1,10 +1,11 @@
from __future__ import annotations from __future__ import annotations
from typing import List from typing import List
from solana.rpc.async_api import AsyncClient
from solana.publickey import PublicKey from solana.publickey import PublicKey
from solana.rpc.types import Commitment from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Recent from solana.rpc.commitment import Recent
from solana.rpc.types import Commitment
from .async_utils import load_bytes_data from .async_utils import load_bytes_data
from .open_orders_account import _OpenOrdersAccountCore from .open_orders_account import _OpenOrdersAccountCore

View File

@ -1,9 +1,9 @@
from typing import List, Dict, Any from typing import Any, Dict, List
import requests import requests
from solana.rpc.api import Client as conn # pylint: disable=unused-import # noqa:F401
from solana.publickey import PublicKey from solana.publickey import PublicKey
from solana.rpc.api import Client as conn # pylint: disable=unused-import # noqa:F401
from .market.types import MarketInfo, TokenInfo from .market.types import MarketInfo, TokenInfo
LIVE_MARKETS_URL = "https://raw.githubusercontent.com/project-serum/serum-ts/master/packages/serum/src/markets.json" LIVE_MARKETS_URL = "https://raw.githubusercontent.com/project-serum/serum-ts/master/packages/serum/src/markets.json"

View File

@ -1,12 +1,12 @@
"""Serum Dex Instructions.""" """Serum Dex Instructions."""
from typing import Dict, List, NamedTuple, Optional from typing import Dict, List, NamedTuple, Optional
from construct import Container
from solana.publickey import PublicKey from solana.publickey import PublicKey
from solana.sysvar import SYSVAR_RENT_PUBKEY from solana.sysvar import SYSVAR_RENT_PUBKEY
from solana.transaction import AccountMeta, TransactionInstruction from solana.transaction import AccountMeta, TransactionInstruction
from solana.utils.validate import validate_instruction_keys, validate_instruction_type from solana.utils.validate import validate_instruction_keys, validate_instruction_type
from spl.token.constants import TOKEN_PROGRAM_ID from spl.token.constants import TOKEN_PROGRAM_ID
from construct import Container
from ._layouts.instructions import INSTRUCTIONS_LAYOUT, InstructionType from ._layouts.instructions import INSTRUCTIONS_LAYOUT, InstructionType
from .enums import OrderType, SelfTradeBehavior, Side from .enums import OrderType, SelfTradeBehavior, Side
@ -268,6 +268,36 @@ class CancelOrderByClientIDV2Params(NamedTuple):
"""""" """"""
class CloseOpenOrdersParams(NamedTuple):
"""Cancel order by client ID params."""
open_orders: PublicKey
""""""
owner: PublicKey
""""""
sol_wallet: PublicKey
""""""
market: PublicKey
""""""
program_id: PublicKey = DEFAULT_DEX_PROGRAM_ID
""""""
class InitOpenOrdersParams(NamedTuple):
"""Cancel order by client ID params."""
open_orders: PublicKey
""""""
owner: PublicKey
""""""
market: PublicKey
""""""
market_authority: Optional[PublicKey] = None
""""""
program_id: PublicKey = DEFAULT_DEX_PROGRAM_ID
""""""
def __parse_and_validate_instruction( def __parse_and_validate_instruction(
instruction: TransactionInstruction, instruction_type: InstructionType instruction: TransactionInstruction, instruction_type: InstructionType
) -> Container: ) -> Container:
@ -282,6 +312,8 @@ def __parse_and_validate_instruction(
InstructionType.NEW_ORDER_V3: 12, InstructionType.NEW_ORDER_V3: 12,
InstructionType.CANCEL_ORDER_V2: 6, InstructionType.CANCEL_ORDER_V2: 6,
InstructionType.CANCEL_ORDER_BY_CLIENT_ID_V2: 6, InstructionType.CANCEL_ORDER_BY_CLIENT_ID_V2: 6,
InstructionType.CLOSE_OPEN_ORDERS: 4,
InstructionType.INIT_OPEN_ORDERS: 3,
} }
validate_instruction_keys(instruction, instruction_type_to_length_map[instruction_type]) validate_instruction_keys(instruction, instruction_type_to_length_map[instruction_type])
data = INSTRUCTIONS_LAYOUT.parse(instruction.data) data = INSTRUCTIONS_LAYOUT.parse(instruction.data)
@ -289,7 +321,9 @@ def __parse_and_validate_instruction(
return data return data
def decode_initialize_market(instruction: TransactionInstruction) -> InitializeMarketParams: def decode_initialize_market(
instruction: TransactionInstruction,
) -> InitializeMarketParams:
"""Decode an instialize market instruction and retrieve the instruction params.""" """Decode an instialize market instruction and retrieve the instruction params."""
data = __parse_and_validate_instruction(instruction, InstructionType.INITIALIZE_MARKET) data = __parse_and_validate_instruction(instruction, InstructionType.INITIALIZE_MARKET)
return InitializeMarketParams( return InitializeMarketParams(
@ -382,7 +416,9 @@ def decode_settle_funds(instruction: TransactionInstruction) -> SettleFundsParam
) )
def decode_cancel_order_by_client_id(instruction: TransactionInstruction) -> CancelOrderByClientIDParams: def decode_cancel_order_by_client_id(
instruction: TransactionInstruction,
) -> CancelOrderByClientIDParams:
data = __parse_and_validate_instruction(instruction, InstructionType.CANCEL_ORDER_BY_CLIENT_ID) data = __parse_and_validate_instruction(instruction, InstructionType.CANCEL_ORDER_BY_CLIENT_ID)
return CancelOrderByClientIDParams( return CancelOrderByClientIDParams(
market=instruction.keys[0].pubkey, market=instruction.keys[0].pubkey,
@ -445,6 +481,29 @@ def decode_cancel_order_by_client_id_v2(instruction: TransactionInstruction) ->
) )
def decode_close_open_orders(
instruction: TransactionInstruction,
) -> CloseOpenOrdersParams:
return CloseOpenOrdersParams(
open_orders=instruction.keys[0].pubkey,
owner=instruction.keys[1].pubkey,
sol_wallet=instruction.keys[2].pubkey,
market=instruction.keys[3].pubkey,
)
def decode_init_open_orders(
instruction: TransactionInstruction,
) -> InitOpenOrdersParams:
market_authority = instruction.keys[3].pubkey if len(instruction.keys) == 4 else None
return InitOpenOrdersParams(
open_orders=instruction.keys[0].pubkey,
owner=instruction.keys[1].pubkey,
market=instruction.keys[2].pubkey,
market_authority=market_authority,
)
def initialize_market(params: InitializeMarketParams) -> TransactionInstruction: def initialize_market(params: InitializeMarketParams) -> TransactionInstruction:
"""Generate a transaction instruction to initialize a Serum market.""" """Generate a transaction instruction to initialize a Serum market."""
return TransactionInstruction( return TransactionInstruction(
@ -519,7 +578,10 @@ def match_orders(params: MatchOrdersParams) -> TransactionInstruction:
], ],
program_id=params.program_id, program_id=params.program_id,
data=INSTRUCTIONS_LAYOUT.build( data=INSTRUCTIONS_LAYOUT.build(
dict(instruction_type=InstructionType.MATCH_ORDER, args=dict(limit=params.limit)) dict(
instruction_type=InstructionType.MATCH_ORDER,
args=dict(limit=params.limit),
)
), ),
) )
@ -534,7 +596,10 @@ def consume_events(params: ConsumeEventsParams) -> TransactionInstruction:
keys=keys, keys=keys,
program_id=params.program_id, program_id=params.program_id,
data=INSTRUCTIONS_LAYOUT.build( data=INSTRUCTIONS_LAYOUT.build(
dict(instruction_type=InstructionType.CONSUME_EVENTS, args=dict(limit=params.limit)) dict(
instruction_type=InstructionType.CONSUME_EVENTS,
args=dict(limit=params.limit),
)
), ),
) )
@ -582,7 +647,9 @@ def settle_funds(params: SettleFundsParams) -> TransactionInstruction:
) )
def cancel_order_by_client_id(params: CancelOrderByClientIDParams) -> TransactionInstruction: def cancel_order_by_client_id(
params: CancelOrderByClientIDParams,
) -> TransactionInstruction:
"""Generate a transaction instruction to cancel order by client id.""" """Generate a transaction instruction to cancel order by client id."""
return TransactionInstruction( return TransactionInstruction(
keys=[ keys=[
@ -668,7 +735,9 @@ def cancel_order_v2(params: CancelOrderV2Params) -> TransactionInstruction:
) )
def cancel_order_by_client_id_v2(params: CancelOrderByClientIDV2Params) -> TransactionInstruction: def cancel_order_by_client_id_v2(
params: CancelOrderByClientIDV2Params,
) -> TransactionInstruction:
"""Generate a transaction instruction to cancel order by client id.""" """Generate a transaction instruction to cancel order by client id."""
return TransactionInstruction( return TransactionInstruction(
keys=[ keys=[
@ -689,3 +758,35 @@ def cancel_order_by_client_id_v2(params: CancelOrderByClientIDV2Params) -> Trans
) )
), ),
) )
def close_open_orders(params: CloseOpenOrdersParams) -> TransactionInstruction:
"""Generate a transaction instruction to close open orders account."""
return TransactionInstruction(
keys=[
AccountMeta(pubkey=params.open_orders, is_signer=False, is_writable=True),
AccountMeta(pubkey=params.owner, is_signer=True, is_writable=False),
AccountMeta(pubkey=params.sol_wallet, is_signer=False, is_writable=True),
AccountMeta(pubkey=params.market, is_signer=False, is_writable=False),
],
program_id=params.program_id,
data=INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.CLOSE_OPEN_ORDERS, args=dict())),
)
def init_open_orders(params: InitOpenOrdersParams) -> TransactionInstruction:
"""Generate a transaction instruction to initialize open orders account."""
touched_keys = [
AccountMeta(pubkey=params.open_orders, is_signer=False, is_writable=True),
AccountMeta(pubkey=params.owner, is_signer=True, is_writable=False),
AccountMeta(pubkey=params.market, is_signer=False, is_writable=False),
]
if params.market_authority:
touched_keys.append(
AccountMeta(pubkey=params.market_authority, is_signer=False, is_writable=False),
)
return TransactionInstruction(
keys=touched_keys,
program_id=params.program_id,
data=INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.INIT_OPEN_ORDERS, args=dict())),
)

View File

@ -1,4 +1,4 @@
from .market import Market # noqa: F401
from .async_market import AsyncMarket # noqa: F401 from .async_market import AsyncMarket # noqa: F401
from .market import Market # noqa: F401
from .orderbook import OrderBook # noqa: F401 from .orderbook import OrderBook # noqa: F401
from .state import MarketState as State # noqa: F401 from .state import MarketState as State # noqa: F401

View File

@ -9,17 +9,17 @@ from solana.rpc.async_api import AsyncClient
from solana.rpc.types import RPCResponse, TxOpts from solana.rpc.types import RPCResponse, TxOpts
from solana.transaction import Transaction from solana.transaction import Transaction
from pyserum import instructions
import pyserum.market.types as t import pyserum.market.types as t
from pyserum import instructions
from .._layouts.open_orders import OPEN_ORDERS_LAYOUT from .._layouts.open_orders import OPEN_ORDERS_LAYOUT
from ..enums import OrderType, Side
from ..async_open_orders_account import AsyncOpenOrdersAccount from ..async_open_orders_account import AsyncOpenOrdersAccount
from ..async_utils import load_bytes_data from ..async_utils import load_bytes_data
from ..enums import OrderType, Side
from ._internal.queue import decode_event_queue, decode_request_queue from ._internal.queue import decode_event_queue, decode_request_queue
from .core import MarketCore
from .orderbook import OrderBook from .orderbook import OrderBook
from .state import MarketState from .state import MarketState
from .core import MarketCore
LAMPORTS_PER_SOL = 1000000000 LAMPORTS_PER_SOL = 1000000000

View File

@ -11,15 +11,14 @@ from solana.rpc.types import RPCResponse
from solana.system_program import CreateAccountParams, create_account from solana.system_program import CreateAccountParams, create_account
from solana.transaction import Transaction, TransactionInstruction from solana.transaction import Transaction, TransactionInstruction
from spl.token.constants import ACCOUNT_LEN, TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT from spl.token.constants import ACCOUNT_LEN, TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT
from spl.token.instructions import CloseAccountParams from spl.token.instructions import CloseAccountParams, InitializeAccountParams, close_account, initialize_account
from spl.token.instructions import InitializeAccountParams, close_account, initialize_account
from pyserum import instructions
import pyserum.market.types as t import pyserum.market.types as t
from pyserum import instructions
from ..async_open_orders_account import AsyncOpenOrdersAccount
from ..enums import OrderType, SelfTradeBehavior, Side from ..enums import OrderType, SelfTradeBehavior, Side
from ..open_orders_account import OpenOrdersAccount, make_create_account_instruction from ..open_orders_account import OpenOrdersAccount, make_create_account_instruction
from ..async_open_orders_account import AsyncOpenOrdersAccount
from ._internal.queue import decode_event_queue from ._internal.queue import decode_event_queue
from .orderbook import OrderBook from .orderbook import OrderBook
from .state import MarketState from .state import MarketState

View File

@ -9,17 +9,17 @@ from solana.rpc.api import Client
from solana.rpc.types import RPCResponse, TxOpts from solana.rpc.types import RPCResponse, TxOpts
from solana.transaction import Transaction from solana.transaction import Transaction
from pyserum import instructions
import pyserum.market.types as t import pyserum.market.types as t
from pyserum import instructions
from .._layouts.open_orders import OPEN_ORDERS_LAYOUT from .._layouts.open_orders import OPEN_ORDERS_LAYOUT
from ..enums import OrderType, Side from ..enums import OrderType, Side
from ..open_orders_account import OpenOrdersAccount from ..open_orders_account import OpenOrdersAccount
from ..utils import load_bytes_data from ..utils import load_bytes_data
from ._internal.queue import decode_event_queue, decode_request_queue from ._internal.queue import decode_event_queue, decode_request_queue
from .core import MarketCore
from .orderbook import OrderBook from .orderbook import OrderBook
from .state import MarketState from .state import MarketState
from .core import MarketCore
LAMPORTS_PER_SOL = 1000000000 LAMPORTS_PER_SOL = 1000000000

View File

@ -7,7 +7,7 @@ from solana.publickey import PublicKey
from solana.rpc.api import Client from solana.rpc.api import Client
from solana.rpc.async_api import AsyncClient from solana.rpc.async_api import AsyncClient
from pyserum import utils, async_utils from pyserum import async_utils, utils
from .._layouts.market import MARKET_LAYOUT from .._layouts.market import MARKET_LAYOUT
from .types import AccountFlags from .types import AccountFlags

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
import base64 import base64
from typing import List, NamedTuple, TypeVar, Type, Tuple from typing import List, NamedTuple, Tuple, Type, TypeVar
from solana.publickey import PublicKey from solana.publickey import PublicKey
from solana.rpc.api import Client from solana.rpc.api import Client

View File

@ -1,5 +1,5 @@
from typing import Dict
import asyncio import asyncio
from typing import Dict
import pytest import pytest
from solana.keypair import Keypair from solana.keypair import Keypair
@ -7,8 +7,8 @@ from solana.publickey import PublicKey
from solana.rpc.api import Client from solana.rpc.api import Client
from solana.rpc.async_api import AsyncClient from solana.rpc.async_api import AsyncClient
from pyserum.connection import conn
from pyserum.async_connection import async_conn from pyserum.async_connection import async_conn
from pyserum.connection import conn
@pytest.mark.integration @pytest.mark.integration

View File

@ -1,6 +1,6 @@
# pylint: disable=R0801 # pylint: disable=R0801
import pytest
import httpx import httpx
import pytest
from pyserum.async_connection import get_live_markets, get_token_mints from pyserum.async_connection import get_live_markets, get_token_mints
from pyserum.market.types import MarketInfo, TokenInfo from pyserum.market.types import MarketInfo, TokenInfo

View File

@ -113,3 +113,36 @@ def test_settle_funds():
) )
instruction = inlib.settle_funds(params) instruction = inlib.settle_funds(params)
assert inlib.decode_settle_funds(instruction) == params assert inlib.decode_settle_funds(instruction) == params
def test_close_open_orders():
"""Test settle funds."""
params = inlib.CloseOpenOrdersParams(
open_orders=PublicKey(0),
owner=PublicKey(1),
sol_wallet=PublicKey(2),
market=PublicKey(3),
)
instruction = inlib.close_open_orders(params)
assert inlib.decode_close_open_orders(instruction) == params
def test_init_open_orders():
"""Test settle funds."""
params = inlib.InitOpenOrdersParams(
open_orders=PublicKey(0), owner=PublicKey(1), market=PublicKey(2), market_authority=None
)
instruction = inlib.init_open_orders(params)
assert inlib.decode_init_open_orders(instruction) == params
def test_init_open_orders_with_authority():
"""Test settle funds."""
params = inlib.InitOpenOrdersParams(
open_orders=PublicKey(0),
owner=PublicKey(1),
market=PublicKey(2),
market_authority=PublicKey(3),
)
instruction = inlib.init_open_orders(params)
assert inlib.decode_init_open_orders(instruction) == params