Skip to main content

Instruction Discriminators

Every instruction in the PerpetualInstruction enum is encoded using Borsh.

The first byte of serialized data is the enum variant index, also called the instruction discriminator.

This byte determines which instruction the program executes.


How It Works

When serialized:

<u8 discriminator> + <borsh-encoded fields>

Example:

Buffer.concat([
Buffer.from([7]), // TradeFutures discriminator
...encodedFields
])

The Rust side resolves it via:

pub fn discriminator(&self) -> u8 {
match self {
Self::Deposit { .. } => 0,
...
}
}

Complete Discriminator Table

User Balance Management (0–2)

DiscriminatorInstruction
0Deposit
1Withdraw
2WithdrawTo

Order Management (3–8)

DiscriminatorInstruction
3OpenLimit
4CloseLimit
5CancelLimit
6MatchOrder
7TradeFutures
8ClosePosition

Conditional Orders (9–11)

DiscriminatorInstruction
9PlaceConditionalOrder
10CancelConditionalOrder
11PlaceBracketOrder

Triggers & Execution (12–14)

DiscriminatorInstruction
12TriggerOrders
13TriggerOpenOrder
14TriggerCloseOrder

Liquidation (15–18)

DiscriminatorInstruction
15ClearingTaker
16LiquidateMakerDeal
17LiquidateMakerDeals
18AfterLiquidateTaker

Public Pool Operations (19–21)

DiscriminatorInstruction
19InitializePublicPool
20AddPublicLiquidity
21WithdrawPublicLiquidity

Private Pool Operations (22–24)

DiscriminatorInstruction
22InitializePrivatePool
23AddPrivateLiquidity
24WithdrawPrivateLiquidity

Pool Management (25–27)

DiscriminatorInstruction
25MoveToPublic
26AddMarginAmount
27SetUserParam

Pool CPI (Internal) (28–29)

DiscriminatorInstruction
28PoolMatchOrder
29PoolCloseOrder

Admin Functions (30–39)

DiscriminatorInstruction
30SetUnderlying
31SetKeepers
32SetTradeFeeAddr
33SetMaintenanceMarginRate
34SetTradeFeeRate
35SetLimitFeeRate
36SetStartStop
37SetPoolPublishAppendRate
38InitializeConfig
39InitializeUserAccount

View Functions (42–47)

DiscriminatorInstruction
42GetAccountInfo
43GetPosition
44GetOrder
45GetLimitedOrder
46GetPNLByCertainPosition
47CheckTakerRiskStatus

Important Notes

  • Discriminators must match Rust enum ordering exactly.
  • Changing enum order will break compatibility.
  • Always hardcode discriminator values in frontend builders.
  • Never rely on implicit enum ordering in TypeScript.

Example: Manual Encoding

const data = Buffer.concat([
Buffer.from([0]), // Deposit
writeU128LE("1000000000000000000")
]);
const data = Buffer.concat([
Buffer.from([7]), // TradeFutures
...encodedFields
]);

Validation Rule

Before decoding:

pub fn validate_instruction_data(data: &[u8]) -> Result<(), ProgramError> {
if data.is_empty() {
return Err(InstructionUnpackError.into());
}
Ok(())
}

The first byte determines the variant.


This table is the canonical reference for all client-side instruction builders.