Skip to main content
phoenix-rise-litesvm-test provides deterministic LiteSVM fixtures for Phoenix program integration tests. It loads Phoenix Eternal and Ember, optionally Hawkeye and Flight, creates fake USDC collateral, initializes markets, seeds actors, and exposes helpers for replaying setup and action transactions. References:

Setup

The fixture helpers look for local protocol SBF artifacts. In CI you can use the fixture package directly; locally, set the artifact paths or point the helpers at a Phoenix repo checkout.
export PHOENIX_REPO_ROOT=/path/to/phoenix
export RISE_SDK_LOCALNET_REQUIRE_PROGRAMS=1
For the example program tests, also build or point to the example program SBF:
export RISE_EXAMPLE_PROGRAM_SO=/path/to/rise_example_program.so

Context

Build a SdkLocalnetContext, load any extra program under test, execute fixture setup, then send instructions through the context.
Rust
use phoenix_rise_litesvm_test::{
    SdkLocalnetContext, SdkLocalnetProgram, default_sdk_localnet_fixture,
    find_sdk_localnet_program_paths,
};
use solana_pubkey::Pubkey;

let fixture = default_sdk_localnet_fixture()?;
let program_paths = find_sdk_localnet_program_paths()
    .expect("Phoenix protocol SBF artifacts are required");
let program_id = Pubkey::new_unique();

let mut context = SdkLocalnetContext::new_with_programs(
    fixture,
    program_paths,
    [SdkLocalnetProgram::new(program_id, "target/deploy/my_program.so")],
);

context.execute_setup();
context.svm.warp_to_slot(200);
Source: litesvm-test/src/context.rs.

Prime Markets

Most order tests need current oracle and spline prices plus maker liquidity. The example program primes those from fixture transactions before sending taker instructions.
Rust
pub fn prime_market(context: &mut SdkLocalnetContext) {
    context.send_fixture_transaction("oracleSetPrices");
    context.send_fixture_transaction("splineUpdatePrices");
    context.send_fixture_transaction("orderbookPlaceLevels");
}
Source: example-program/tests/common/mod.rs.

Test A Flow

Write tests against the behavior you expect from your program, not against Phoenix internals. This example places a market order, places a limit order, extracts the order id from return data/log helpers, and cancels it.
Rust
#[test]
fn market_limit_and_cancel_flow_executes() {
    let Some((mut context, program_id)) = setup_context() else {
        return;
    };
    prime_market(&mut context);

    let actor = context.actor("taker0");
    let market = context.market("BTC");

    let market_logs = send_and_print_logs(
        &mut context,
        with_compute_budget(place_market_ix(
            &context,
            &actor,
            &market,
            program_id,
            Side::Bid,
            BTC_BASE_LOTS,
            quote_lots_for_price(&market, 100_500.0, 6, BTC_BASE_LOTS),
            11,
            OrderFlags::None,
        )),
        &actor.seed,
        "place-market-order",
    );
    assert_logs_contain(&market_logs, "Phoenix place market order");
}
Source: example-program/tests/market_orders.rs.

TypeScript LiteSVM

The TypeScript SDK tests use the litesvm npm package with the same generated localnet fixture. The published package exposes the fixture at @ellipsis-labs/rise/test-fixtures/default-localnet.json; the public repo’s test harness shows how to load local SBF artifacts, replay setup transactions, attach fixture signers, and send SDK-built instructions into LiteSVM.
TypeScript
import { LiteSVM } from "litesvm";
import defaultFixture from "@ellipsis-labs/rise/test-fixtures/default-localnet.json";

const vm = new LiteSVM();

// Load local Phoenix/Ember/Hawkeye SBF artifacts, fund fixture signers,
// then replay defaultFixture.setupTransactions before sending test actions.
Source: ts/tests/test-harness/localnet.ts. The public harness wraps those steps in createSdkLocalnetContext and exposes helpers for fixture-backed market params, account contexts, signing, and transaction submission.
TypeScript
import {
  buildMarketOrderPacketFromMarketParams,
  buildPlaceMarketOrderIxResolved,
  Side,
} from "@ellipsis-labs/rise";
import {
  buildSdkLocalnetMarketParams,
  buildSdkLocalnetPlaceOrderContext,
  createSdkLocalnetContext,
} from "./test-harness/litesvm";

const context = await createSdkLocalnetContext();
const actor = context.getActor("taker0");
const orderPacket = buildMarketOrderPacketFromMarketParams(
  {
    side: Side.Bid,
    priceLimitUsd: "101000",
    baseUnits: "0.01",
    minBaseUnitsToFill: "0.01",
  },
  buildSdkLocalnetMarketParams(context, "BTC")
);

const ix = buildPlaceMarketOrderIxResolved({
  ...buildSdkLocalnetPlaceOrderContext(context, {
    actorName: actor.name,
    symbol: "BTC",
  }),
  orderPacket,
});

await context.sendInstructions([ix], {
  feePayerSeed: actor.seed,
  label: "sdk-built-place-market-order",
});
Source: ts/tests/sdk-localnet-vm.test.ts. The broader TypeScript flow tests cover the same localnet surface as the Rust fixture tests: deposits, withdrawals, market orders, limit orders, stop losses, conditionals, Hawkeye return data, and isolated subaccounts.

Fixture Metadata

When your off-chain test client needs the same market params as LiteSVM, build PhoenixMetadata from the fixture instead of calling mainnet APIs.
Rust
use phoenix_rise_litesvm_test::{
    default_sdk_localnet_fixture, phoenix_metadata_from_fixture,
};

let fixture = default_sdk_localnet_fixture()?;
let metadata = phoenix_metadata_from_fixture(&fixture)?;
let builder = PhoenixTxBuilder::new(&metadata);
Use this pattern to test PhoenixTxBuilder flows against the local fixture and keep transaction construction deterministic.