diff --git a/explorer/src/components/instruction/SerumDetailsCard.tsx b/explorer/src/components/instruction/SerumDetailsCard.tsx index 7f4964316..59154687a 100644 --- a/explorer/src/components/instruction/SerumDetailsCard.tsx +++ b/explorer/src/components/instruction/SerumDetailsCard.tsx @@ -6,15 +6,22 @@ import { reportError } from "utils/sentry"; import { decodeCancelOrder, decodeCancelOrderByClientId, + decodeCancelOrderByClientIdV2, + decodeCancelOrderV2, + decodeCloseOpenOrders, decodeConsumeEvents, + decodeConsumeEventsPermissioned, + decodeDisableMarket, decodeInitializeMarket, + decodeInitOpenOrders, decodeMatchOrders, decodeNewOrder, + decodeNewOrderV3, + decodePrune, decodeSettleFunds, - parseSerumInstructionCode, + decodeSweepFees, parseSerumInstructionKey, parseSerumInstructionTitle, - SERUM_DECODED_MAX, } from "./serum/types"; import { NewOrderDetailsCard } from "./serum/NewOrderDetailsCard"; import { MatchOrdersDetailsCard } from "./serum/MatchOrdersDetailsCard"; @@ -23,6 +30,15 @@ import { ConsumeEventsDetailsCard } from "./serum/ConsumeEventsDetails"; import { CancelOrderDetailsCard } from "./serum/CancelOrderDetails"; import { CancelOrderByClientIdDetailsCard } from "./serum/CancelOrderByClientIdDetails"; import { SettleFundsDetailsCard } from "./serum/SettleFundsDetailsCard"; +import { DisableMarketDetailsCard } from "./serum/DisableMarketDetails"; +import { SweepFeesDetailsCard } from "./serum/SweepFeesDetails"; +import { NewOrderV3DetailsCard } from "./serum/NewOrderV3DetailsCard"; +import { CancelOrderV2DetailsCard } from "./serum/CancelOrderV2Details"; +import { CancelOrderByClientIdV2DetailsCard } from "./serum/CancelOrderByClientIdV2Details"; +import { CloseOpenOrdersDetailsCard } from "./serum/CloseOpenOrdersDetails"; +import { InitOpenOrdersDetailsCard } from "./serum/InitOpenOrdersDetails"; +import { PruneDetailsCard } from "./serum/PruneDetails"; +import { ConsumeEventsPermissionedDetailsCard } from "./serum/ConsumeEventsPermissionedDetails"; export function SerumDetailsCard(props: { ix: TransactionInstruction; @@ -39,46 +55,81 @@ export function SerumDetailsCard(props: { let title; try { title = parseSerumInstructionTitle(ix); - const code = parseSerumInstructionCode(ix); - - if (code <= SERUM_DECODED_MAX) { - switch (parseSerumInstructionKey(ix)) { - case "initializeMarket": - return ( - - ); - case "newOrder": - return ; - case "matchOrders": - return ( - - ); - case "consumeEvents": - return ( - - ); - case "cancelOrder": - return ( - - ); - case "cancelOrderByClientId": - return ( - - ); - case "settleFunds": - return ( - - ); - } + switch (parseSerumInstructionKey(ix)) { + case "initializeMarket": + return ( + + ); + case "newOrder": + return ; + case "matchOrders": + return ( + + ); + case "consumeEvents": + return ( + + ); + case "cancelOrder": + return ( + + ); + case "settleFunds": + return ( + + ); + case "cancelOrderByClientId": + return ( + + ); + case "disableMarket": + return ( + + ); + case "sweepFees": + return ; + case "newOrderV3": + return ; + case "cancelOrderV2": + return ( + + ); + case "cancelOrderByClientIdV2": + return ( + + ); + case "closeOpenOrders": + return ( + + ); + case "initOpenOrders": + return ( + + ); + case "prune": + return ; + case "consumeEventsPermissioned": + return ( + + ); } } catch (error) { reportError(error, { diff --git a/explorer/src/components/instruction/serum/CancelOrderByClientIdDetails.tsx b/explorer/src/components/instruction/serum/CancelOrderByClientIdDetails.tsx index 74cb066eb..2f9f6707f 100644 --- a/explorer/src/components/instruction/serum/CancelOrderByClientIdDetails.tsx +++ b/explorer/src/components/instruction/serum/CancelOrderByClientIdDetails.tsx @@ -26,34 +26,34 @@ export function CancelOrderByClientIdDetailsCard(props: { Market -
+
Open Orders -
+
Request Queue -
+
- Owner + Open Orders Owner -
+
Client Id - {info.clientId.toString(10)} + {info.data.clientId.toString(10)} ); diff --git a/explorer/src/components/instruction/serum/CancelOrderByClientIdV2Details.tsx b/explorer/src/components/instruction/serum/CancelOrderByClientIdV2Details.tsx new file mode 100644 index 000000000..066aadf2c --- /dev/null +++ b/explorer/src/components/instruction/serum/CancelOrderByClientIdV2Details.tsx @@ -0,0 +1,74 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { CancelOrderByClientIdV2 } from "./types"; + +export function CancelOrderByClientIdV2DetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: CancelOrderByClientIdV2; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Market + +
+ + + + + Bids + +
+ + + + + Asks + +
+ + + + + Open Orders + +
+ + + + + Open Orders Owner + +
+ + + + + Event Queue + +
+ + + + + Client Id + {info.data.clientId.toString(10)} + + + ); +} diff --git a/explorer/src/components/instruction/serum/CancelOrderDetails.tsx b/explorer/src/components/instruction/serum/CancelOrderDetails.tsx index 40d176a85..1086d1112 100644 --- a/explorer/src/components/instruction/serum/CancelOrderDetails.tsx +++ b/explorer/src/components/instruction/serum/CancelOrderDetails.tsx @@ -33,44 +33,44 @@ export function CancelOrderDetailsCard(props: { Market -
+
Open Orders -
+
+ + + + + Open Orders Owner + +
Request Queue -
- - - - - Owner - -
+
Side - {info.side} + {info.data.side} Open Orders Slot - {info.openOrdersSlot} + {info.data.openOrdersSlot} Order Id - {info.orderId.toString(10)} + {info.data.orderId.toString(10)} ); diff --git a/explorer/src/components/instruction/serum/CancelOrderV2Details.tsx b/explorer/src/components/instruction/serum/CancelOrderV2Details.tsx new file mode 100644 index 000000000..5340ad480 --- /dev/null +++ b/explorer/src/components/instruction/serum/CancelOrderV2Details.tsx @@ -0,0 +1,86 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { CancelOrderV2 } from "./types"; + +export function CancelOrderV2DetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: CancelOrderV2; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Market + +
+ + + + + Bids + +
+ + + + + Asks + +
+ + + + + Open Orders + +
+ + + + + Open Orders Owner + +
+ + + + + Event Queue + +
+ + + + + Side + {info.data.side} + + + + Order Id + {info.data.orderId.toString(10)} + + + ); +} diff --git a/explorer/src/components/instruction/serum/CloseOpenOrdersDetails.tsx b/explorer/src/components/instruction/serum/CloseOpenOrdersDetails.tsx new file mode 100644 index 000000000..9e879826f --- /dev/null +++ b/explorer/src/components/instruction/serum/CloseOpenOrdersDetails.tsx @@ -0,0 +1,62 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { CloseOpenOrders } from "./types"; + +export function CloseOpenOrdersDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: CloseOpenOrders; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Open Orders + +
+ + + + + Open Orders Owner + +
+ + + + + Rent Receiver + +
+ + + + + Market + +
+ + + + ); +} diff --git a/explorer/src/components/instruction/serum/ConsumeEventsDetails.tsx b/explorer/src/components/instruction/serum/ConsumeEventsDetails.tsx index 705ab4c05..3b1f23438 100644 --- a/explorer/src/components/instruction/serum/ConsumeEventsDetails.tsx +++ b/explorer/src/components/instruction/serum/ConsumeEventsDetails.tsx @@ -33,21 +33,21 @@ export function ConsumeEventsDetailsCard(props: { Market -
+
Event Queue -
+
Open Orders Accounts - {info.openOrdersAccounts.map((account, index) => { + {info.accounts.openOrders.map((account, index) => { return
; })} @@ -55,7 +55,7 @@ export function ConsumeEventsDetailsCard(props: { Limit - {info.limit} + {info.data.limit} ); diff --git a/explorer/src/components/instruction/serum/ConsumeEventsPermissionedDetails.tsx b/explorer/src/components/instruction/serum/ConsumeEventsPermissionedDetails.tsx new file mode 100644 index 000000000..9366cf6c7 --- /dev/null +++ b/explorer/src/components/instruction/serum/ConsumeEventsPermissionedDetails.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { ConsumeEventsPermissioned } from "./types"; + +export function ConsumeEventsPermissionedDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: ConsumeEventsPermissioned; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Market + +
+ + + + + Event Queue + +
+ + + + + Crank Authority + +
+ + + + + Open Orders Accounts + + {info.accounts.openOrders.map((account, index) => { + return
; + })} + + + + + Limit + {info.data.limit} + + + ); +} diff --git a/explorer/src/components/instruction/serum/DisableMarketDetails.tsx b/explorer/src/components/instruction/serum/DisableMarketDetails.tsx new file mode 100644 index 000000000..920614cfe --- /dev/null +++ b/explorer/src/components/instruction/serum/DisableMarketDetails.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { DisableMarket } from "./types"; + +export function DisableMarketDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: DisableMarket; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Market + +
+ + + + + Disable Authority + +
+ + + + ); +} diff --git a/explorer/src/components/instruction/serum/InitOpenOrdersDetails.tsx b/explorer/src/components/instruction/serum/InitOpenOrdersDetails.tsx new file mode 100644 index 000000000..a2c898c17 --- /dev/null +++ b/explorer/src/components/instruction/serum/InitOpenOrdersDetails.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { InitOpenOrders } from "./types"; + +export function InitOpenOrdersDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: InitOpenOrders; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Open Orders + +
+ + + + + Open Orders Owner + +
+ + + + + Market + +
+ + + + {info.accounts.openOrdersMarketAuthority && ( + + Open Orders Market Authority + +
+ + + )} + + ); +} diff --git a/explorer/src/components/instruction/serum/InitializeMarketDetailsCard.tsx b/explorer/src/components/instruction/serum/InitializeMarketDetailsCard.tsx index 50d28aa4e..be9d124fe 100644 --- a/explorer/src/components/instruction/serum/InitializeMarketDetailsCard.tsx +++ b/explorer/src/components/instruction/serum/InitializeMarketDetailsCard.tsx @@ -33,91 +33,93 @@ export function InitializeMarketDetailsCard(props: { Market -
+
Request Queue -
+
Event Queue -
+
Bids -
+
Asks -
+
Base Vault -
+
Quote Vault -
+
Base Mint -
+
Quote Mint -
+
Base Lot Size - {info.baseLotSize.toString(10)} + {info.data.baseLotSize.toString(10)} Quote Lot Size - {info.quoteLotSize.toString(10)} + {info.data.quoteLotSize.toString(10)} Fee Rate Bps - {info.feeRateBps} + {info.data.feeRateBps} Quote Dust Threshold - {info.quoteDustThreshold.toString(10)} + {info.data.quoteDustThreshold.toString(10)} Vault Signer Nonce - {info.vaultSignerNonce.toString(10)} + + {info.data.vaultSignerNonce.toString(10)} + ); diff --git a/explorer/src/components/instruction/serum/MatchOrdersDetailsCard.tsx b/explorer/src/components/instruction/serum/MatchOrdersDetailsCard.tsx index 248442b65..02975ca4b 100644 --- a/explorer/src/components/instruction/serum/MatchOrdersDetailsCard.tsx +++ b/explorer/src/components/instruction/serum/MatchOrdersDetailsCard.tsx @@ -33,55 +33,41 @@ export function MatchOrdersDetailsCard(props: { Market -
+
Request Queue -
+
Event Queue -
+
Bids -
+
Asks -
- - - - - Base Vault - -
- - - - - Quote Vault - -
+
Limit - {info.limit} + {info.data.limit} ); diff --git a/explorer/src/components/instruction/serum/NewOrderDetailsCard.tsx b/explorer/src/components/instruction/serum/NewOrderDetailsCard.tsx index f5850d0ee..105321078 100644 --- a/explorer/src/components/instruction/serum/NewOrderDetailsCard.tsx +++ b/explorer/src/components/instruction/serum/NewOrderDetailsCard.tsx @@ -33,75 +33,75 @@ export function NewOrderDetailsCard(props: { Market -
+
Open Orders -
+
Request Queue -
+
Payer -
+
- Owner + Open Orders Owner -
+
Base Vault -
+
Quote Vault -
+
Side - {info.side} + {info.data.side} Order Type - {info.orderType} + {info.data.orderType} Limit Price - {info.limitPrice.toString(10)} + {info.data.limitPrice.toString(10)} Max Quantity - {info.maxQuantity.toString(10)} + {info.data.maxQuantity.toString(10)} Client Id - {info.clientId.toString(10)} + {info.data.clientId.toString(10)} ); diff --git a/explorer/src/components/instruction/serum/NewOrderV3DetailsCard.tsx b/explorer/src/components/instruction/serum/NewOrderV3DetailsCard.tsx new file mode 100644 index 000000000..a6b243afd --- /dev/null +++ b/explorer/src/components/instruction/serum/NewOrderV3DetailsCard.tsx @@ -0,0 +1,152 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { NewOrderV3 } from "./types"; + +export function NewOrderV3DetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: NewOrderV3; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Market + +
+ + + + + Open Orders + +
+ + + + + Request Queue + +
+ + + + + Event Queue + +
+ + + + + Bids + +
+ + + + + Asks + +
+ + + + + Payer + +
+ + + + + Open Orders Owner + +
+ + + + + Base Vault + +
+ + + + + Quote Vault + +
+ + + + {info.accounts.feeDiscountPubkey && ( + + Fee Discount + +
+ + + )} + + + Side + {info.data.side.toUpperCase()} + + + + Order Type + {info.data.orderType} + + + + Limit Price + {info.data.limitPrice.toString(10)} + + + + Max Base Quantity + + {info.data.maxBaseQuantity.toString(10)} + + + + + Max Quote Quantity + + {info.data.maxQuoteQuantity.toString(10)} + + + + + Client Id + {info.data.clientId.toString(10)} + + + + Match Iteration Limit + {info.data.limit} + + + ); +} diff --git a/explorer/src/components/instruction/serum/PruneDetails.tsx b/explorer/src/components/instruction/serum/PruneDetails.tsx new file mode 100644 index 000000000..a95c65a5b --- /dev/null +++ b/explorer/src/components/instruction/serum/PruneDetails.tsx @@ -0,0 +1,88 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { Prune } from "./types"; + +export function PruneDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: Prune; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Market + +
+ + + + + Bids + +
+ + + + + Asks + +
+ + + + + Prune Authority + +
+ + + + + Open Orders + +
+ + + + + Open Orders Owner + +
+ + + + + Event Queue + +
+ + + + + Iteration Limit + {info.data.limit} + + + ); +} diff --git a/explorer/src/components/instruction/serum/SettleFundsDetailsCard.tsx b/explorer/src/components/instruction/serum/SettleFundsDetailsCard.tsx index cb8d812d8..22bd90557 100644 --- a/explorer/src/components/instruction/serum/SettleFundsDetailsCard.tsx +++ b/explorer/src/components/instruction/serum/SettleFundsDetailsCard.tsx @@ -33,64 +33,68 @@ export function SettleFundsDetailsCard(props: { Market -
+
Open Orders -
+
- Owner + Open Orders Owner -
+
Base Vault -
+
Quote Vault -
+
Base Wallet -
+
Quote Wallet -
+
Vault Signer -
+
- {info.referrerQuoteWallet && ( + {info.accounts.referrerQuoteWallet && ( Referrer Quote Wallet -
+
)} diff --git a/explorer/src/components/instruction/serum/SweepFeesDetails.tsx b/explorer/src/components/instruction/serum/SweepFeesDetails.tsx new file mode 100644 index 000000000..9b3dd99d6 --- /dev/null +++ b/explorer/src/components/instruction/serum/SweepFeesDetails.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import { SignatureResult, TransactionInstruction } from "@solana/web3.js"; +import { InstructionCard } from "../InstructionCard"; +import { Address } from "components/common/Address"; +import { SweepFees } from "./types"; + +export function SweepFeesDetailsCard(props: { + ix: TransactionInstruction; + index: number; + result: SignatureResult; + info: SweepFees; + innerCards?: JSX.Element[]; + childIndex?: number; +}) { + const { ix, index, result, info, innerCards, childIndex } = props; + + return ( + + + Program + +
+ + + + + Market + +
+ + + + + Quote Vault + +
+ + + + + Fee Sweeping Authority + +
+ + + + + Fee Receiver + +
+ + + + + Vault Signer + +
+ + + + ); +} diff --git a/explorer/src/components/instruction/serum/types.ts b/explorer/src/components/instruction/serum/types.ts index 6318390b7..a2d6c4139 100644 --- a/explorer/src/components/instruction/serum/types.ts +++ b/explorer/src/components/instruction/serum/types.ts @@ -1,11 +1,13 @@ /* eslint-disable @typescript-eslint/no-redeclare */ import { decodeInstruction, MARKETS } from "@project-serum/serum"; -import { PublicKey, TransactionInstruction } from "@solana/web3.js"; -import BN from "bn.js"; -import { enums, number, optional, type, Infer, create } from "superstruct"; +import { + AccountMeta, + PublicKey, + TransactionInstruction, +} from "@solana/web3.js"; +import { enums, number, type, Infer, create } from "superstruct"; import { BigNumFromString } from "validators/bignum"; -import { PublicKeyFromString } from "validators/pubkey"; const SERUM_PROGRAM_IDS = [ "4ckmDgGdxQoPDLUkDT3vHgSAkzA3QRdNq5ywwY4sUSJn", @@ -20,25 +22,44 @@ export const Side = enums(["buy", "sell"]); export type OrderType = Infer; export const OrderType = enums(["limit", "ioc", "postOnly"]); +export type SelfTradeBehavior = Infer; +export const SelfTradeBehavior = enums([ + "decrementTake", + "cancelProvide", + "abortTransaction", +]); + +function getOptionalKey( + keys: AccountMeta[], + index: number +): PublicKey | undefined { + if (index < keys.length) { + return keys[index].pubkey; + } else { + return undefined; + } +} + export type InitializeMarket = { - market: PublicKey; - requestQueue: PublicKey; - eventQueue: PublicKey; - bids: PublicKey; - asks: PublicKey; - baseVault: PublicKey; - quoteVault: PublicKey; - baseMint: PublicKey; - quoteMint: PublicKey; - baseLotSize: BN; - quoteLotSize: BN; - feeRateBps: number; - vaultSignerNonce: BN; - quoteDustThreshold: BN; programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + requestQueue: PublicKey; + eventQueue: PublicKey; + bids: PublicKey; + asks: PublicKey; + baseVault: PublicKey; + quoteVault: PublicKey; + baseMint: PublicKey; + quoteMint: PublicKey; + openOrdersMarketAuthority?: PublicKey; + pruneAuthority?: PublicKey; + crankAuthority?: PublicKey; + }; }; -export const InitializeMarketDecode = type({ +export const InitializeMarketInstruction = type({ baseLotSize: BigNumFromString, quoteLotSize: BigNumFromString, feeRateBps: number(), @@ -49,251 +70,506 @@ export const InitializeMarketDecode = type({ export function decodeInitializeMarket( ix: TransactionInstruction ): InitializeMarket { - const decoded = create( - decodeInstruction(ix.data).initializeMarket, - InitializeMarketDecode - ); - - let initializeMarket: InitializeMarket = { - market: ix.keys[0].pubkey, - requestQueue: ix.keys[1].pubkey, - eventQueue: ix.keys[2].pubkey, - bids: ix.keys[3].pubkey, - asks: ix.keys[4].pubkey, - baseVault: ix.keys[5].pubkey, - quoteVault: ix.keys[6].pubkey, - baseMint: ix.keys[7].pubkey, - quoteMint: ix.keys[8].pubkey, + return { programId: ix.programId, - baseLotSize: decoded.baseLotSize as BN, - quoteLotSize: decoded.quoteLotSize as BN, - feeRateBps: decoded.feeRateBps, - quoteDustThreshold: decoded.quoteDustThreshold as BN, - vaultSignerNonce: decoded.vaultSignerNonce as BN, + data: create( + decodeInstruction(ix.data).initializeMarket, + InitializeMarketInstruction + ), + accounts: { + market: ix.keys[0].pubkey, + requestQueue: ix.keys[1].pubkey, + eventQueue: ix.keys[2].pubkey, + bids: ix.keys[3].pubkey, + asks: ix.keys[4].pubkey, + baseVault: ix.keys[5].pubkey, + quoteVault: ix.keys[6].pubkey, + baseMint: ix.keys[7].pubkey, + quoteMint: ix.keys[8].pubkey, + openOrdersMarketAuthority: getOptionalKey(ix.keys, 10), + pruneAuthority: getOptionalKey(ix.keys, 11), + crankAuthority: getOptionalKey(ix.keys, 12), + }, }; - - return initializeMarket; } export type NewOrder = { - market: PublicKey; - openOrders: PublicKey; - requestQueue: PublicKey; - payer: PublicKey; - owner: PublicKey; - baseVault: PublicKey; - quoteVault: PublicKey; programId: PublicKey; - feeDiscountPubkey?: PublicKey; - side: Side; - limitPrice: BN; - maxQuantity: BN; - orderType: OrderType; - clientId: BN; + data: Infer; + accounts: { + market: PublicKey; + openOrders: PublicKey; + requestQueue: PublicKey; + payer: PublicKey; + openOrdersOwner: PublicKey; + baseVault: PublicKey; + quoteVault: PublicKey; + feeDiscountPubkey?: PublicKey; + }; }; -export const NewOrderDecode = type({ +export const NewOrderInstruction = type({ side: Side, limitPrice: BigNumFromString, maxQuantity: BigNumFromString, orderType: OrderType, clientId: BigNumFromString, - feeDiscountPubkey: optional(PublicKeyFromString), }); export function decodeNewOrder(ix: TransactionInstruction): NewOrder { - const decoded = create(decodeInstruction(ix.data).newOrder, NewOrderDecode); - - let newOrder: NewOrder = { - market: ix.keys[0].pubkey, - openOrders: ix.keys[1].pubkey, - requestQueue: ix.keys[2].pubkey, - payer: ix.keys[3].pubkey, - owner: ix.keys[4].pubkey, - baseVault: ix.keys[5].pubkey, - quoteVault: ix.keys[6].pubkey, + return { programId: ix.programId, - side: decoded.side as Side, - limitPrice: decoded.limitPrice as BN, - maxQuantity: decoded.maxQuantity as BN, - orderType: decoded.orderType as OrderType, - clientId: decoded.clientId as BN, + data: create(decodeInstruction(ix.data).newOrder, NewOrderInstruction), + accounts: { + market: ix.keys[0].pubkey, + openOrders: ix.keys[1].pubkey, + requestQueue: ix.keys[2].pubkey, + payer: ix.keys[3].pubkey, + openOrdersOwner: ix.keys[4].pubkey, + baseVault: ix.keys[5].pubkey, + quoteVault: ix.keys[6].pubkey, + feeDiscountPubkey: getOptionalKey(ix.keys, 9), + }, }; - - if (decoded.feeDiscountPubkey) { - newOrder.feeDiscountPubkey = decoded.feeDiscountPubkey; - } - - return newOrder; } export type MatchOrders = { - market: PublicKey; - requestQueue: PublicKey; - eventQueue: PublicKey; - bids: PublicKey; - asks: PublicKey; - baseVault: PublicKey; - quoteVault: PublicKey; - limit: number; programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + requestQueue: PublicKey; + eventQueue: PublicKey; + bids: PublicKey; + asks: PublicKey; + }; }; -export const MatchOrdersDecode = type({ +export const MatchOrdersInstruction = type({ limit: number(), }); export function decodeMatchOrders(ix: TransactionInstruction): MatchOrders { - const decoded = create( - decodeInstruction(ix.data).matchOrders, - MatchOrdersDecode - ); - - const matchOrders: MatchOrders = { - market: ix.keys[0].pubkey, - requestQueue: ix.keys[1].pubkey, - eventQueue: ix.keys[2].pubkey, - bids: ix.keys[3].pubkey, - asks: ix.keys[4].pubkey, - baseVault: ix.keys[5].pubkey, - quoteVault: ix.keys[6].pubkey, + return { programId: ix.programId, - limit: decoded.limit, + data: create( + decodeInstruction(ix.data).matchOrders, + MatchOrdersInstruction + ), + accounts: { + market: ix.keys[0].pubkey, + requestQueue: ix.keys[1].pubkey, + eventQueue: ix.keys[2].pubkey, + bids: ix.keys[3].pubkey, + asks: ix.keys[4].pubkey, + }, }; - - return matchOrders; } export type ConsumeEvents = { - market: PublicKey; - eventQueue: PublicKey; - openOrdersAccounts: PublicKey[]; - limit: number; programId: PublicKey; + data: Infer; + accounts: { + openOrders: PublicKey[]; + market: PublicKey; + eventQueue: PublicKey; + }; }; -export const ConsumeEventsDecode = type({ +export const ConsumeEventsInstruction = type({ limit: number(), }); export function decodeConsumeEvents(ix: TransactionInstruction): ConsumeEvents { - const decoded = create( - decodeInstruction(ix.data).consumeEvents, - ConsumeEventsDecode - ); - - const consumeEvents: ConsumeEvents = { - openOrdersAccounts: ix.keys.slice(0, -2).map((k) => k.pubkey), - market: ix.keys[ix.keys.length - 2].pubkey, - eventQueue: ix.keys[ix.keys.length - 3].pubkey, + return { programId: ix.programId, - limit: decoded.limit, + data: create( + decodeInstruction(ix.data).consumeEvents, + ConsumeEventsInstruction + ), + accounts: { + openOrders: ix.keys.slice(0, -4).map((k) => k.pubkey), + market: ix.keys[ix.keys.length - 4].pubkey, + eventQueue: ix.keys[ix.keys.length - 3].pubkey, + }, }; - - return consumeEvents; } export type CancelOrder = { - market: PublicKey; - openOrders: PublicKey; - owner: PublicKey; - requestQueue: PublicKey; - side: "buy" | "sell"; - orderId: BN; - openOrdersSlot: number; programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + openOrders: PublicKey; + requestQueue: PublicKey; + openOrdersOwner: PublicKey; + }; }; -export const CancelOrderDecode = type({ +export const CancelOrderInstruction = type({ side: Side, orderId: BigNumFromString, openOrdersSlot: number(), }); export function decodeCancelOrder(ix: TransactionInstruction): CancelOrder { - const decoded = create( - decodeInstruction(ix.data).cancelOrder, - CancelOrderDecode - ); - - const cancelOrder: CancelOrder = { - market: ix.keys[0].pubkey, - openOrders: ix.keys[1].pubkey, - requestQueue: ix.keys[2].pubkey, - owner: ix.keys[3].pubkey, + return { programId: ix.programId, - openOrdersSlot: decoded.openOrdersSlot, - orderId: decoded.orderId as BN, - side: decoded.side, + data: create( + decodeInstruction(ix.data).cancelOrder, + CancelOrderInstruction + ), + accounts: { + market: ix.keys[0].pubkey, + openOrders: ix.keys[1].pubkey, + requestQueue: ix.keys[2].pubkey, + openOrdersOwner: ix.keys[3].pubkey, + }, }; +} - return cancelOrder; +export type SettleFunds = { + programId: PublicKey; + accounts: { + market: PublicKey; + openOrders: PublicKey; + openOrdersOwner: PublicKey; + baseVault: PublicKey; + quoteVault: PublicKey; + baseWallet: PublicKey; + quoteWallet: PublicKey; + vaultSigner: PublicKey; + referrerQuoteWallet?: PublicKey; + }; +}; + +export function decodeSettleFunds(ix: TransactionInstruction): SettleFunds { + return { + programId: ix.programId, + accounts: { + market: ix.keys[0].pubkey, + openOrders: ix.keys[1].pubkey, + openOrdersOwner: ix.keys[2].pubkey, + baseVault: ix.keys[3].pubkey, + quoteVault: ix.keys[4].pubkey, + baseWallet: ix.keys[5].pubkey, + quoteWallet: ix.keys[6].pubkey, + vaultSigner: ix.keys[7].pubkey, + referrerQuoteWallet: getOptionalKey(ix.keys, 9), + }, + }; } export type CancelOrderByClientId = { - market: PublicKey; - openOrders: PublicKey; - owner: PublicKey; - requestQueue: PublicKey; - clientId: BN; programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + openOrders: PublicKey; + requestQueue: PublicKey; + openOrdersOwner: PublicKey; + }; }; -export const CancelOrderByClientIdDecode = type({ +export const CancelOrderByClientIdInstruction = type({ clientId: BigNumFromString, }); export function decodeCancelOrderByClientId( ix: TransactionInstruction ): CancelOrderByClientId { - const decoded = create( - decodeInstruction(ix.data).cancelOrderByClientId, - CancelOrderByClientIdDecode - ); - - const cancelOrderByClientId: CancelOrderByClientId = { - market: ix.keys[0].pubkey, - openOrders: ix.keys[1].pubkey, - requestQueue: ix.keys[2].pubkey, - owner: ix.keys[3].pubkey, + return { programId: ix.programId, - clientId: decoded.clientId as BN, + data: create( + decodeInstruction(ix.data).cancelOrderByClientId, + CancelOrderByClientIdInstruction + ), + accounts: { + market: ix.keys[0].pubkey, + openOrders: ix.keys[1].pubkey, + requestQueue: ix.keys[2].pubkey, + openOrdersOwner: ix.keys[3].pubkey, + }, }; - - return cancelOrderByClientId; } -export type SettleFunds = { - market: PublicKey; - openOrders: PublicKey; - owner: PublicKey; - baseVault: PublicKey; - quoteVault: PublicKey; - baseWallet: PublicKey; - quoteWallet: PublicKey; - vaultSigner: PublicKey; +export type DisableMarket = { programId: PublicKey; - referrerQuoteWallet?: PublicKey; + accounts: { + market: PublicKey; + disableAuthority: PublicKey; + }; }; -export function decodeSettleFunds(ix: TransactionInstruction): SettleFunds { - let settleFunds: SettleFunds = { - market: ix.keys[0].pubkey, - openOrders: ix.keys[1].pubkey, - owner: ix.keys[2].pubkey, - baseVault: ix.keys[3].pubkey, - quoteVault: ix.keys[4].pubkey, - baseWallet: ix.keys[5].pubkey, - quoteWallet: ix.keys[6].pubkey, - vaultSigner: ix.keys[7].pubkey, +export function decodeDisableMarket(ix: TransactionInstruction): DisableMarket { + return { programId: ix.programId, + accounts: { + market: ix.keys[0].pubkey, + disableAuthority: ix.keys[1].pubkey, + }, }; +} - if (ix.keys.length > 9) { - settleFunds.referrerQuoteWallet = ix.keys[9].pubkey; - } +export type SweepFees = { + programId: PublicKey; + accounts: { + market: PublicKey; + quoteVault: PublicKey; + feeSweepingAuthority: PublicKey; + quoteFeeReceiver: PublicKey; + vaultSigner: PublicKey; + }; +}; - return settleFunds; +export function decodeSweepFees(ix: TransactionInstruction): SweepFees { + return { + programId: ix.programId, + accounts: { + market: ix.keys[0].pubkey, + quoteVault: ix.keys[1].pubkey, + feeSweepingAuthority: ix.keys[2].pubkey, + quoteFeeReceiver: ix.keys[3].pubkey, + vaultSigner: ix.keys[4].pubkey, + }, + }; +} + +export type NewOrderV3 = { + programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + openOrders: PublicKey; + requestQueue: PublicKey; + eventQueue: PublicKey; + bids: PublicKey; + asks: PublicKey; + payer: PublicKey; + openOrdersOwner: PublicKey; + baseVault: PublicKey; + quoteVault: PublicKey; + feeDiscountPubkey?: PublicKey; + }; +}; + +export const NewOrderV3Instruction = type({ + side: Side, + limitPrice: BigNumFromString, + maxBaseQuantity: BigNumFromString, + maxQuoteQuantity: BigNumFromString, + selfTradeBehavior: SelfTradeBehavior, + orderType: OrderType, + clientId: BigNumFromString, + limit: number(), +}); + +export function decodeNewOrderV3(ix: TransactionInstruction): NewOrderV3 { + return { + programId: ix.programId, + data: create(decodeInstruction(ix.data).newOrderV3, NewOrderV3Instruction), + accounts: { + market: ix.keys[0].pubkey, + openOrders: ix.keys[1].pubkey, + requestQueue: ix.keys[2].pubkey, + eventQueue: ix.keys[3].pubkey, + bids: ix.keys[4].pubkey, + asks: ix.keys[5].pubkey, + payer: ix.keys[6].pubkey, + openOrdersOwner: ix.keys[7].pubkey, + baseVault: ix.keys[8].pubkey, + quoteVault: ix.keys[9].pubkey, + feeDiscountPubkey: getOptionalKey(ix.keys, 12), + }, + }; +} + +export type CancelOrderV2 = { + programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + bids: PublicKey; + asks: PublicKey; + openOrders: PublicKey; + openOrdersOwner: PublicKey; + eventQueue: PublicKey; + }; +}; + +export const CancelOrderV2Instruction = type({ + side: Side, + orderId: BigNumFromString, +}); + +export function decodeCancelOrderV2(ix: TransactionInstruction): CancelOrderV2 { + return { + programId: ix.programId, + data: create( + decodeInstruction(ix.data).cancelOrderV2, + CancelOrderV2Instruction + ), + accounts: { + market: ix.keys[0].pubkey, + bids: ix.keys[1].pubkey, + asks: ix.keys[2].pubkey, + openOrders: ix.keys[3].pubkey, + openOrdersOwner: ix.keys[4].pubkey, + eventQueue: ix.keys[5].pubkey, + }, + }; +} + +export type CancelOrderByClientIdV2 = { + programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + bids: PublicKey; + asks: PublicKey; + openOrders: PublicKey; + openOrdersOwner: PublicKey; + eventQueue: PublicKey; + }; +}; + +export const CancelOrderByClientIdV2Instruction = type({ + clientId: BigNumFromString, +}); + +export function decodeCancelOrderByClientIdV2( + ix: TransactionInstruction +): CancelOrderByClientIdV2 { + return { + programId: ix.programId, + data: create( + decodeInstruction(ix.data).cancelOrderByClientIdV2, + CancelOrderByClientIdV2Instruction + ), + accounts: { + market: ix.keys[0].pubkey, + bids: ix.keys[1].pubkey, + asks: ix.keys[2].pubkey, + openOrders: ix.keys[3].pubkey, + openOrdersOwner: ix.keys[4].pubkey, + eventQueue: ix.keys[5].pubkey, + }, + }; +} + +export type CloseOpenOrders = { + programId: PublicKey; + accounts: { + openOrders: PublicKey; + openOrdersOwner: PublicKey; + rentReceiver: PublicKey; + market: PublicKey; + }; +}; + +export function decodeCloseOpenOrders( + ix: TransactionInstruction +): CloseOpenOrders { + return { + programId: ix.programId, + accounts: { + openOrders: ix.keys[0].pubkey, + openOrdersOwner: ix.keys[1].pubkey, + rentReceiver: ix.keys[2].pubkey, + market: ix.keys[3].pubkey, + }, + }; +} + +export type InitOpenOrders = { + programId: PublicKey; + accounts: { + openOrders: PublicKey; + openOrdersOwner: PublicKey; + market: PublicKey; + openOrdersMarketAuthority?: PublicKey; + }; +}; + +export function decodeInitOpenOrders( + ix: TransactionInstruction +): InitOpenOrders { + return { + programId: ix.programId, + accounts: { + openOrders: ix.keys[0].pubkey, + openOrdersOwner: ix.keys[1].pubkey, + market: ix.keys[2].pubkey, + openOrdersMarketAuthority: ix.keys[4].pubkey, + }, + }; +} + +export type Prune = { + programId: PublicKey; + data: Infer; + accounts: { + market: PublicKey; + bids: PublicKey; + asks: PublicKey; + pruneAuthority: PublicKey; + openOrders: PublicKey; + openOrdersOwner: PublicKey; + eventQueue: PublicKey; + }; +}; + +export const PruneInstruction = type({ + limit: number(), +}); + +export function decodePrune(ix: TransactionInstruction): Prune { + return { + programId: ix.programId, + data: create(decodeInstruction(ix.data).prune, PruneInstruction), + accounts: { + market: ix.keys[0].pubkey, + bids: ix.keys[1].pubkey, + asks: ix.keys[2].pubkey, + pruneAuthority: ix.keys[3].pubkey, + openOrders: ix.keys[4].pubkey, + openOrdersOwner: ix.keys[5].pubkey, + eventQueue: ix.keys[6].pubkey, + }, + }; +} + +export type ConsumeEventsPermissioned = { + programId: PublicKey; + data: Infer; + accounts: { + openOrders: PublicKey[]; + market: PublicKey; + eventQueue: PublicKey; + crankAuthority: PublicKey; + }; +}; + +export const ConsumeEventsPermissionedInstruction = type({ + limit: number(), +}); + +export function decodeConsumeEventsPermissioned( + ix: TransactionInstruction +): ConsumeEventsPermissioned { + return { + programId: ix.programId, + data: create( + decodeInstruction(ix.data).consumeEventsPermissioned, + ConsumeEventsPermissionedInstruction + ), + accounts: { + openOrders: ix.keys.slice(0, -3).map((k) => k.pubkey), + market: ix.keys[ix.keys.length - 3].pubkey, + eventQueue: ix.keys[ix.keys.length - 2].pubkey, + crankAuthority: ix.keys[ix.keys.length - 1].pubkey, + }, + }; } export function isSerumInstruction(instruction: TransactionInstruction) { @@ -326,16 +602,18 @@ const SERUM_CODE_LOOKUP: { [key: number]: string } = { 3: "Consume Events", 4: "Cancel Order", 5: "Settle Funds", - 6: "Cancel Order By Client Id", + 6: "Cancel Order by Client Id", 7: "Disable Market", 8: "Sweep Fees", - 9: "New Order", - 10: "New Order", - 11: "Cancel Order", - 12: "Cancel Order By Client Id", + 9: "New Order v2", + 10: "New Order v3", + 11: "Cancel Order v2", + 12: "Cancel Order by Client Id v2", 13: "Send Take", 14: "Close Open Orders", 15: "Init Open Orders", + 16: "Prune", + 17: "Consume Events Permissioned", }; export function parseSerumInstructionCode(instruction: TransactionInstruction) {