diff --git a/bin/cancel-my-orders b/bin/cancel-my-orders index 3e07340..1822c26 100755 --- a/bin/cancel-my-orders +++ b/bin/cancel-my-orders @@ -57,6 +57,7 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context: f"No open orders on {market_operations.market.fully_qualified_symbol}" ) else: + signatures: typing.Sequence[str] if mango.PerpMarket.isa(market_operations.market): cancel_all = mango.PerpMarketOperations.ensure( market_operations @@ -65,13 +66,14 @@ with mango.ContextBuilder.from_command_line_parameters(args) as context: signers: mango.CombinableInstructions = ( mango.CombinableInstructions.from_wallet(wallet) ) - cancel_all_signatures = (signers + cancel_all).execute(context) - mango.output(f"Cancelling all perp orders: {cancel_all_signatures}") + signatures = (signers + cancel_all).execute(context) + mango.output(f"Cancelling all perp orders: {signatures}") else: - signatures: typing.List[str] = [] + individual_signatures: typing.List[str] = [] for order in orders: mango.output("Cancelling:", order) - signatures += market_operations.cancel_order(order) + individual_signatures += market_operations.cancel_order(order) + signatures = individual_signatures if args.wait: mango.output("Waiting on transaction signatures:") diff --git a/mango/instructions.py b/mango/instructions.py index aa8746f..ec96177 100644 --- a/mango/instructions.py +++ b/mango/instructions.py @@ -933,6 +933,104 @@ def build_perp_cancel_order_instructions( return CombinableInstructions(signers=[], instructions=instructions) +# # 🥭 build_perp_cancel_all_orders_instructions function +# +# Builds the instructions necessary for cancelling all perp orders. +# +def build_perp_cancel_all_orders_instructions( + context: Context, + wallet: Wallet, + account: IAccount, + perp_market_details: PerpMarketDetails, + limit: Decimal = Decimal(32), +) -> CombinableInstructions: + # Accounts expected by this instruction (seems to be the same as CANCEL_PERP_ORDER and CANCEL_PERP_ORDER_BY_CLIENT_ID): + # { isSigner: false, isWritable: false, pubkey: mangoGroupPk }, + # { isSigner: false, isWritable: true, pubkey: mangoAccountPk }, + # { isSigner: true, isWritable: false, pubkey: ownerPk }, + # { isSigner: false, isWritable: true, pubkey: perpMarketPk }, + # { isSigner: false, isWritable: true, pubkey: bidsPk }, + # { isSigner: false, isWritable: true, pubkey: asksPk }, + instructions = [ + TransactionInstruction( + keys=[ + AccountMeta( + is_signer=False, is_writable=False, pubkey=account.group_address + ), + AccountMeta(is_signer=False, is_writable=True, pubkey=account.address), + AccountMeta(is_signer=True, is_writable=False, pubkey=wallet.address), + AccountMeta( + is_signer=False, + is_writable=True, + pubkey=perp_market_details.address, + ), + AccountMeta( + is_signer=False, is_writable=True, pubkey=perp_market_details.bids + ), + AccountMeta( + is_signer=False, is_writable=True, pubkey=perp_market_details.asks + ), + ], + program_id=context.mango_program_address, + data=layouts.CANCEL_ALL_PERP_ORDERS.build({"limit": limit}), + ) + ] + return CombinableInstructions(signers=[], instructions=instructions) + + +# # 🥭 build_perp_cancel_all_side_instructions function +# +# Builds the instructions necessary for cancelling all perp orders on a given side. +# +def build_perp_cancel_all_side_instructions( + context: Context, + wallet: Wallet, + account: IAccount, + perp_market_details: PerpMarketDetails, + side: Side, + limit: Decimal = Decimal(32), +) -> CombinableInstructions: + # { buy: 0, sell: 1 } + raw_side: int = 1 if side == Side.SELL else 0 + + # /// Cancel all perp open orders for one side of the book + # /// + # /// Accounts expected: 6 + # /// 0. `[]` mango_group_ai - MangoGroup + # /// 1. `[writable]` mango_account_ai - MangoAccount + # /// 2. `[signer]` owner_ai - Owner of Mango Account + # /// 3. `[writable]` perp_market_ai - PerpMarket + # /// 4. `[writable]` bids_ai - Bids acc + # /// 5. `[writable]` asks_ai - Asks acc + instructions = [ + TransactionInstruction( + keys=[ + AccountMeta( + is_signer=False, is_writable=False, pubkey=account.group_address + ), + AccountMeta(is_signer=False, is_writable=True, pubkey=account.address), + AccountMeta(is_signer=True, is_writable=False, pubkey=wallet.address), + AccountMeta( + is_signer=False, + is_writable=True, + pubkey=perp_market_details.address, + ), + AccountMeta( + is_signer=False, is_writable=True, pubkey=perp_market_details.bids + ), + AccountMeta( + is_signer=False, is_writable=True, pubkey=perp_market_details.asks + ), + ], + program_id=context.mango_program_address, + data=layouts.CANCEL_PERP_ORDER_SIDE.build( + {"side": raw_side, "limit": limit} + ), + ) + ] + return CombinableInstructions(signers=[], instructions=instructions) + + # /// Place an order on a perp market # /// # /// In case this order is matched, the corresponding order structs on both @@ -1054,51 +1152,6 @@ def build_perp_place_order_instructions( return CombinableInstructions(signers=[], instructions=instructions) -# # 🥭 build_perp_cancel_all_orders_instructions function -# -# Builds the instructions necessary for cancelling all perp orders. -# -def build_perp_cancel_all_orders_instructions( - context: Context, - wallet: Wallet, - account: IAccount, - perp_market_details: PerpMarketDetails, - limit: Decimal = Decimal(32), -) -> CombinableInstructions: - # Accounts expected by this instruction (seems to be the same as CANCEL_PERP_ORDER and CANCEL_PERP_ORDER_BY_CLIENT_ID): - # { isSigner: false, isWritable: false, pubkey: mangoGroupPk }, - # { isSigner: false, isWritable: true, pubkey: mangoAccountPk }, - # { isSigner: true, isWritable: false, pubkey: ownerPk }, - # { isSigner: false, isWritable: true, pubkey: perpMarketPk }, - # { isSigner: false, isWritable: true, pubkey: bidsPk }, - # { isSigner: false, isWritable: true, pubkey: asksPk }, - instructions = [ - TransactionInstruction( - keys=[ - AccountMeta( - is_signer=False, is_writable=False, pubkey=account.group_address - ), - AccountMeta(is_signer=False, is_writable=True, pubkey=account.address), - AccountMeta(is_signer=True, is_writable=False, pubkey=wallet.address), - AccountMeta( - is_signer=False, - is_writable=True, - pubkey=perp_market_details.address, - ), - AccountMeta( - is_signer=False, is_writable=True, pubkey=perp_market_details.bids - ), - AccountMeta( - is_signer=False, is_writable=True, pubkey=perp_market_details.asks - ), - ], - program_id=context.mango_program_address, - data=layouts.CANCEL_ALL_PERP_ORDERS.build({"limit": limit}), - ) - ] - return CombinableInstructions(signers=[], instructions=instructions) - - def build_perp_consume_events_instructions( context: Context, group: IGroup, diff --git a/mango/layouts/layouts.py b/mango/layouts/layouts.py index 47d8951..70f8e75 100644 --- a/mango/layouts/layouts.py +++ b/mango/layouts/layouts.py @@ -1629,6 +1629,22 @@ def _encode( ) +# /// Cancel all perp open orders for one side of the book +# /// +# /// Accounts expected: 6 +# /// 0. `[]` mango_group_ai - MangoGroup +# /// 1. `[writable]` mango_account_ai - MangoAccount +# /// 2. `[signer]` owner_ai - Owner of Mango Account +# /// 3. `[writable]` perp_market_ai - PerpMarket +# /// 4. `[writable]` bids_ai - Bids acc +# /// 5. `[writable]` asks_ai - Asks acc +CANCEL_PERP_ORDER_SIDE = construct.Struct( + "variant" / construct.Const(57, construct.BytesInteger(4, swapped=True)), + "side" / DecimalAdapter(1), # { buy: 0, sell: 1 } + "limit" / DecimalAdapter(1), +) + + # /// https://github.com/blockworks-foundation/mango-v3/pull/97/ # /// Set delegate authority to mango account which can do everything regular account can do # /// except Withdraw and CloseMangoAccount. Set to Pubkey::default() to revoke delegate @@ -1792,7 +1808,7 @@ def _encode( 54: UNSPECIFIED, # RESOLVE_DUST, 55: CREATE_MANGO_ACCOUNT, # CREATE_MANGO_ACCOUNT, 56: UNSPECIFIED, # UPGRADE_MANGO_ACCOUNT_V0_V1, - 57: UNSPECIFIED, # CANCEL_PERP_ORDER_SIDE, + 57: CANCEL_PERP_ORDER_SIDE, # CANCEL_PERP_ORDER_SIDE, 58: SET_DELEGATE, # SET_DELEGATE, 59: UNSPECIFIED, # CHANGE_SPOT_MARKET_PARAMS, 60: CREATE_SPOT_OPEN_ORDERS, # CREATE_SPOT_OPEN_ORDERS, diff --git a/mango/mangoinstruction.py b/mango/mangoinstruction.py index 6ae4e33..277dedf 100644 --- a/mango/mangoinstruction.py +++ b/mango/mangoinstruction.py @@ -476,7 +476,7 @@ def describe_parameters(self) -> str: elif instruction_type == InstructionType.UpgradeMangoAccountV0V1: pass elif instruction_type == InstructionType.CancelPerpOrderSide: - pass + additional_data = f"side: {Side.from_value(self.instruction_data.side)}, limit: {self.instruction_data.limit}" elif instruction_type == InstructionType.SetDelegate: pass elif instruction_type == InstructionType.ChangeSpotMarketParams: