Skip to main content
Use the Rise Rust CPI surface when your Solana program already has AccountInfo handles and needs to invoke Phoenix, Ember, Flight, or Hawkeye directly. The SDK does not fetch accounts or derive every PDA at CPI time. Your program validates and resolves accounts, then adapts them into typed CPI contexts such as phoenix::PlaceMarketOrder, phoenix::PlaceStopLoss, or hawkeye::ViewMargin. Reference implementations:

Example Program Map

Use the example program as the source of truth for complete account lists. The docs below show the shape of each CPI, but the linked files show the full outer instruction, parameter struct, account metas, LiteSVM test setup, and log assertions.

Dependencies

Most on-chain programs should depend on the phoenix-rise facade with only the cpi feature enabled. That profile exposes account byte decoders, instruction layouts, and Pinocchio CPI helpers without the HTTP, WebSocket, RPC, or transaction-builder graph.
Cargo
If you only want the instruction and CPI layer, depend on phoenix-rise-ix directly.
Cargo
The public example program uses the facade from the local workspace:
Cargo
Source: example-program/Cargo.toml.

Imports

Using the facade crate:
Rust
Using the low-level instruction crate directly:
Rust

CPI Shape

The typed CPI contexts are account-context structs. They borrow accounts from your outer instruction and encode the expected Phoenix account order for you. They do not own accounts and they do not resolve missing accounts from chain state. Phoenix order CPIs usually need:
  • Phoenix program id and log authority.
  • Global config and PerpAssetMap.
  • Trader signer or delegated authority, plus the trader account.
  • Market orderbook and spline collection.
  • Dynamic global_trader_index accounts.
  • Dynamic active_trader_buffer accounts.
  • Optional accounts for stop losses, conditionals, Hawkeye, Ember, or Flight.
The example program keeps a fixed account prefix and passes the dynamic global_trader_index and active_trader_buffer accounts at the tail. The tail counts are carried in instruction data, so the loader can split the account slice without allocation.
Rust
Source: example-program/src/common.rs.

Market Context

A useful integration pattern is to create one outer context that knows how to load and validate your instruction accounts, then add small helper methods that project those accounts into the SDK’s typed CPI contexts.
Rust
Source: example-program/src/market.rs.

Invoke Phoenix

Once your outer context can build the typed CPI context, the invoke step is small: create CpiScratch, pass instruction-specific args, and let the SDK write the account metas and instruction data.
Rust
CpiScratch owns fixed-size stack buffers for account infos, account metas, and instruction data. For dynamic market accounts, size it to your integration’s upper bound and check ctx.account_count() before invoking if the account count is user-controlled. If you already have reusable storage, use CpiBuffers and invoke_with_buffers(...) instead.

Stop Losses And Conditionals

Stop losses and conditional orders follow the same pattern, but the account context includes the funder, position authority, conditional or stop-loss account, and system program. Creating a stop-loss or conditional-order account can incur rent if the account does not already exist.
Rust
Source: example-program/src/place_stop_loss.rs.

Collateral CPIs

Collateral flows often compose Ember and Phoenix CPIs in one outer instruction. The example program wraps fake USDC into Phoenix collateral through Ember, then deposits that collateral into the Phoenix trader account.
Rust
Source: example-program/src/deposit_ember_then_phoenix.rs. Withdrawals reverse the sequence: Phoenix withdraw first, then Ember unwrap. Source: example-program/src/withdraw_phoenix_then_ember.rs.

Subaccount CPIs

Subaccount flows are a good example of composing several typed contexts. The example registers the child trader account, syncs parent capabilities, transfers collateral to the child, then reuses MarketContext to place the child order.
Rust
Source: example-program/src/register_subaccount_sync_transfer_and_market_order.rs.

Return Data

Phoenix order CPIs can return matching-engine data. Decode return data instead of parsing logs.
Rust
Source: example-program/src/common.rs.

Hawkeye Views

Hawkeye is the read-only program for authoritative margin, liquidation-price, BBO, and funding views. Invoke it when local SDK math is not enough and you need the result the on-chain programs would use. Hawkeye writes versioned return data; decode those bytes instead of parsing logs. Hawkeye program id: RiSeVw3ZjNfsaXPRb4mgaqYaEEt41pNNJoDvVh7pgQj. Use it to validate the CPI program account on-chain and to assert that simulation return data came from Hawkeye off-chain.
Hawkeye instructions are normal Solana instructions, so they can be invoked off-chain in a transaction simulation or on-chain through CPI. The current typed Pinocchio CPI helper in the Rust SDK is ix::cpi::hawkeye::ViewMargin; the other views are exposed through off-chain instruction builders and can be mirrored on-chain with the same account metas and discriminators if your program needs them. Sources: rust/ix/src/hawkeye.rs, ts/src/hawkeye.ts, rust/core/src/hawkeye_client.rs, and ts/src/rpc.ts.

On-chain CPI

On-chain programs read Hawkeye return data the same way they read Phoenix return data: invoke the program, call get_return_data() immediately, assert the return-data program id is Hawkeye, then decode the expected struct. Return data is overwritten by the next CPI that sets it, so decode or copy it before another Phoenix or Hawkeye call. The example program invokes hawkeye::ViewMargin after market orders and decodes the return into ViewMarginReturn.
Rust
If you need the manual decode path, use the same guard the helper uses internally.
Rust
Source: example-program/src/market.rs and rust/ix/src/cpi.rs.

Off-chain simulation

For applications and services, prefer the SDK Hawkeye RPC helpers. They build a read-only simulation transaction, validate that return data came from the Hawkeye program id, and decode the bytes into the typed return shape.
If you already have accounts resolved, you can build a Hawkeye instruction directly and still let the SDK decode the return data.
Reference coverage: ts/tests/sdk-localnet-flows.test.ts executes all five Hawkeye views in LiteSVM, and rust/sdk/tests/sdk_localnet_fixture_tests.rs asserts Hawkeye return data is emitted by the expected program id.

Supported CPI Contexts

The typed CPI surface includes:
  • Trader lifecycle: RegisterTrader, SetTraderCapabilitiesDelegated, UpdateTraderState, SyncParentToChild.
  • Order flow: PlaceMarketOrder, PlaceLimitOrder, PlaceMarketOrderDelegated, PlaceMultiLimitOrder, CancelAll, CancelUpTo, CancelOrdersById, CancelAllPlusConditional.
  • Collateral and subaccounts: PhoenixDeposit, PhoenixWithdraw, TransferCollateral, TransferCollateralChildToParent.
  • Stop losses and conditionals: CreateConditionalOrdersAccount, PlaceStopLoss, CancelStopLoss, PlacePositionConditionalOrder, PlaceAttachedConditionalOrder, PlaceLimitOrderWithConditionals, CancelConditionalOrder.
  • Ember collateral movement: ember::EmberDeposit, ember::EmberWithdraw.
  • Hawkeye reads: hawkeye::ViewMargin / hawkeye::HawkeyeViewMargin.
For full account lists and data lengths, inspect rust/ix/src/cpi.rs.

Testing

Use LiteSVM Testing for local integration tests. The example program tests cover deposits, withdrawals, market orders, limit orders, cancels, stop losses, Hawkeye reads, and isolated subaccount collateral flows.