Skip to content
Logo

Local maker testing

Run a perps network on your computer. Use the Rust or TypeScript example to create a maker account, publish a quote and check a fill.

The network provides test wallets and tokens. Use its local URLs and keys throughout this guide.

To use the dashboard for account setup, follow Local dashboard setup after starting the network. Keep the SDK example for publishing quotes.

Before you start

Install dependencies

Expand the scripts for your platform. Read a block, then use its Copy code button to copy it. Use 1a or 1b, then 2. Use 3 for TypeScript or the dashboard. The scripts install tools; they do not start a Solana network.

1a. macOS — build tools and Docker Desktop

Uses Homebrew. If the Xcode tools installer opens, complete it and run this block again. Complete Docker Desktop's first-run setup and wait for its engine to start.

bash <<'BASH'
set -euo pipefail
[[ "$(uname -s)" == Darwin ]] || { echo 'Run this script on macOS.' >&2; exit 1; }
if ! xcode-select -p >/dev/null 2>&1; then
  xcode-select --install
  echo 'Finish the Xcode tools installer, then run this block again.'
  exit 1
fi
if ! command -v brew >/dev/null; then
  for candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do
    if [[ -x "$candidate" ]]; then eval "$("$candidate" shellenv)"; break; fi
  done
fi
if ! command -v brew >/dev/null; then
  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  case "$(uname -m)" in
    arm64) eval "$(/opt/homebrew/bin/brew shellenv)" ;;
    x86_64) eval "$(/usr/local/bin/brew shellenv)" ;;
  esac
fi
brew install git gh protobuf cmake pkg-config openssl@3 python@3.12
if ! command -v docker >/dev/null; then brew install --cask docker-desktop; fi
open -a Docker
BASH
1b. Ubuntu 24.04 or WSL2 — build tools

Use x86-64 Ubuntu 24.04. On Windows, install Ubuntu in WSL2, then run this block in the Ubuntu terminal.

bash <<'BASH'
set -euo pipefail
[[ "$(uname -s)" == Linux && "$(uname -m)" == x86_64 ]] || {
  echo 'Use an x86-64 Ubuntu or WSL2 environment.' >&2; exit 1;
}
# shellcheck source=/dev/null
. /etc/os-release
[[ "$ID" == ubuntu && "$VERSION_ID" == 24.04 ]] || {
  echo 'Use Ubuntu 24.04, including inside WSL2.' >&2; exit 1;
}
sudo apt-get update
sudo apt-get install -y \
  ca-certificates curl git gh python3 python3-venv unzip xz-utils bzip2 \
  clang cmake g++ libclang-dev libssl-dev libudev-dev make perl \
  pkg-config protobuf-compiler zlib1g-dev
BASH

On Windows, enable Docker Desktop's WSL2 integration. On native Ubuntu, use the next block to install Docker Engine. Keep an existing Docker installation.

bash <<'BASH'
set -euo pipefail
if command -v docker >/dev/null; then
  echo 'Docker is already installed. Keep your existing installation.'
  exit 0
fi
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
printf '%s\n' \
  'Types: deb' \
  'URIs: https://download.docker.com/linux/ubuntu' \
  'Suites: noble' \
  'Components: stable' \
  'Architectures: amd64' \
  'Signed-By: /etc/apt/keyrings/docker.asc' \
  | sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker "$(id -un)"
echo 'Sign out and sign in again before using Docker without sudo.'
BASH

Sign out and sign in again after joining the Docker group.

2. All platforms — Rust, Solana and Surfpool

Installs Rust 1.95, Solana 3.1.7 and Surfpool 1.5.0. Selects Rust 1.95 as the default toolchain. The Surfpool archive is checked against its release checksum.

bash <<'BASH'
set -euo pipefail
check_sha256() {
  if command -v sha256sum >/dev/null; then sha256sum -c -; else shasum -a 256 -c -; fi
}
case "$(uname -s)/$(uname -m)" in
  Darwin/arm64) platform=darwin-arm64; checksum=418d1464050cb1e09225b37b907952383f712648544318a0ca7ce13304e7915a ;;
  Darwin/x86_64) platform=darwin-x64; checksum=64ea0d703a52a28b0e80eeb06bae706d9ec6a8e6d4da7ddab820aa2321b74f21 ;;
  Linux/x86_64) platform=linux-x64; checksum=5b20a3b46e60c4f819af7b4da5c3ea211f76041710617841cc23247d15887ddc ;;
  *) echo 'Use macOS, or x86-64 Linux/WSL2.' >&2; exit 1 ;;
esac
if ! command -v rustup >/dev/null && [[ ! -x "$HOME/.cargo/bin/rustup" ]]; then
  curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs \
    | sh -s -- -y --profile minimal --default-toolchain 1.95
fi
export PATH="$HOME/.cargo/bin:$PATH"
rustup toolchain install 1.95 --profile minimal
rustup default 1.95
sh -c "$(curl -fsSL https://release.anza.xyz/v3.1.7/install)"
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT
curl -fsSL \
  "https://github.com/solana-foundation/surfpool/releases/download/v1.5.0/surfpool-$platform.tar.gz" \
  -o "$work_dir/surfpool.tar.gz"
printf '%s  %s\n' "$checksum" "$work_dir/surfpool.tar.gz" | check_sha256
mkdir -p "$HOME/.local/bin" "$HOME/.local/share/flint-maker-tools"
tar -xzf "$work_dir/surfpool.tar.gz" -C "$HOME/.local/bin" surfpool
cat > "$HOME/.local/share/flint-maker-tools/env" <<'PATHS'
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$HOME/.local/share/solana/install/active_release/bin:$HOME/.local/share/flint-maker-tools/node/bin:$HOME/.bun/bin:$PATH"
PATHS
# shellcheck source=/dev/null
. "$HOME/.local/share/flint-maker-tools/env"
rustc +1.95 --version
solana --version | grep -F 'solana-cli 3.1.7'
test "$(surfpool --version)" = 'surfpool 1.5.0'
BASH
. "$HOME/.local/share/flint-maker-tools/env"

For another terminal, load the same paths with . "$HOME/.local/share/flint-maker-tools/env". The server checkout selects its Rust toolchain.

3. TypeScript or dashboard — Node.js and Bun

Skip this block for the Rust-only route. It installs the current Node.js 22 release and Bun 1.3.14 in your home directory. The Node archive is checked against Node's release checksums.

bash <<'BASH'
set -euo pipefail
check_sha256() {
  if command -v sha256sum >/dev/null; then sha256sum -c -; else shasum -a 256 -c -; fi
}
case "$(uname -s)/$(uname -m)" in
  Darwin/arm64) platform=darwin-arm64 ;;
  Darwin/x86_64) platform=darwin-x64 ;;
  Linux/x86_64) platform=linux-x64 ;;
  *) echo 'Use macOS, or x86-64 Linux/WSL2.' >&2; exit 1 ;;
esac
work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT
base=https://nodejs.org/dist/latest-v22.x
curl -fsSL "$base/SHASUMS256.txt" -o "$work_dir/SHASUMS256.txt"
archive="$(awk -v suffix="-$platform.tar.xz" '$2 ~ (suffix "$") {print $2}' "$work_dir/SHASUMS256.txt")"
[[ -n "$archive" && "$archive" != */* && "$archive" != *$'\n'* ]] || {
  echo 'Could not select one Node.js archive.' >&2; exit 1;
}
curl -fsSL "$base/$archive" -o "$work_dir/$archive"
(cd "$work_dir"; grep -F "  $archive" SHASUMS256.txt | check_sha256)
mkdir -p "$HOME/.local/share/flint-maker-tools/node"
tar -xJf "$work_dir/$archive" --strip-components=1 -C "$HOME/.local/share/flint-maker-tools/node"
curl -fsSL https://bun.sh/install | bash -s -- 'bun-v1.3.14'
# shellcheck source=/dev/null
. "$HOME/.local/share/flint-maker-tools/env"
node --version | grep -E '^v22\.'
npm --version
test "$(bun --version)" = '1.3.14'
BASH
. "$HOME/.local/share/flint-maker-tools/env"

Check the tools

git --version
gh --version
python3 --version
protoc --version
rustc +1.95 --version
solana --version
surfpool --version
docker info

If docker info fails, start Docker Desktop or your Docker Engine service before continuing.

Get access

Ask Flint for GitHub read access to:

Then authenticate Git and sign in with gh auth login.

For SDK packages:

  • Rust: get your token from Perps → Developer → Get SDK credentials.
  • TypeScript: obtain GitHub Packages access from Flint.

Follow SDK package setup for registry login.

Download the local environment

Clone the server and select the tested local-environment revision:

git clone https://github.com/superis-labs/flint-server.git
cd flint-server
git fetch origin 7b164580045d3a0da32593693362f3609cc76529
git checkout --detach 7b164580045d3a0da32593693362f3609cc76529

Run the server commands below from this directory.

Environment versions
ComponentVersion or ID
Rust / Solana / Surfpool1.95 / 3.1.7 / 1.5.0
Node.js / Bun22.x / 1.3.14
ClickHouse25.8
Protocol source435c48b3
Maker example SDK / IDL7.0.4 / 0.10.2
Program ID4MxEr7W5f9xtajcTTpTTd5wfdBmwrF72j2NMg6YzXgMo

SDK versions come from the downloaded examples' manifests. Tool versions match the pinned fixture. CI checks both sources when they change.

1. Start ClickHouse

Start a separate ClickHouse container for this environment. Use the version shown below.

docker run -d --name maker-docs-clickhouse --ulimit nofile=262144:262144 \
  -p 127.0.0.1:18123:8123 -e CLICKHOUSE_SKIP_USER_SETUP=1 \
  clickhouse/clickhouse-server:25.8
curl -fsS http://127.0.0.1:18123/ping
export MARGIN_FIXTURE_CLICKHOUSE_URL=http://127.0.0.1:18123

Repeat the ping command until it returns Ok. Use an unused container name and port. If you change the port, update both the mapping and URL.

2. Start the network

For local SDK-token tests, prepare the package registry before this step. Otherwise, continue below.

MARGIN_OFFLINE=true MARGIN_ACCEPTANCE=true TUI_MARGIN_HEADLESS=true make tui-margin

Wait for FLINT MARGIN DEV STACK — ready. Keep this terminal running.

Configure the SDK example

Open .cache/maker-onboarding/manifest.json in the server directory. Select the wallet entries for your example:

ExampleOwnerBot
Rustrust-ownerrust-quoter
TypeScripttypescript-ownertypescript-quoter

Copy these values into the SDK configuration:

SettingManifest value
RPC_URLrpc_url
PUBLIC_ENDPOINTpublic_endpoint
MAKER_ENDPOINTmaker_endpoint
OWNER_KEYPAIRSelected owner entry's keypair_path
QUOTER_KEYPAIRSelected bot entry's keypair_path
TRADER_IDSelected owner entry's trader_id
PERP_IDSelected perps[] entry's linear_perp_id
COLLATERAL_MINT, COLLATERAL_ATOMScollateral_mint, collateral_atoms

The wallets already hold fee SOL and collateral tokens. Use USDC for this test.

3. Create and fund the maker account

Install and configure the SDK example in another terminal. Use the manifest's keys and choose one account-setup route:

  • SDK: follow the file-key steps to run setup, then deposit, once.
  • Dashboard: follow Local dashboard setup to create the account, deposit collateral and grant the manifest's bot key.

Return here to grant quoting permission. Use the SDK example to publish quotes.

Grant quoting permission

Use wallets["admin"].keypair_path as the admin key. From the SDK example directory, grant MAY_QUOTE to your maker:

ADMIN_KEYPAIR='<manifest-admin-key-path>' cargo run --locked -- grant

Keep your maker's TRADER_ID, PERP_ID, RPC and gateway settings for this command.

Open a slot and publish a quote

Follow Open a market slot, then Publish a quote. Keep both quote sides active while you run the fill test.

4. Check a fill

The maker and taker must have no open position in the selected market. Keep both quote sides active and unexpired. Use one writer for this maker and market.

Open another terminal in the server directory. Use:

  • The taker's keypair_path and trader_id from wallets["taker"].
  • Your selected perp ID.
  • The manifest's USDC collateral_mint.
  • Your perps maker ID (TRADER_ID) and a small lot count within both quote sides' depth.
cargo build --release --locked -p tui-margin --bin margin-taker-proof
target/release/margin-taker-proof \
  --rpc-url <manifest-rpc-url> --keypair <manifest-taker-key-path> \
  --trader-id <manifest-taker-id> --perp-id <selected-manifest-perp-id> \
  --collateral-mint <selected-manifest-collateral-mint> \
  --makers <maker-id> --lots <small-lot-count-within-quoted-depth>

The command creates a missing taker account, deposits collateral, opens and closes IOC positions, and settles both accounts. It uses USDC for PnL settlement.

Check the result

In the maker SDK example, run fills and account. Check the buy and sell fills. The maker position should be zero after the round trip.

Check the taker account with its ID. The prefix changes the ID for this command only:

TRADER_ID='<manifest-taker-id>' cargo run --locked -- account

The taker position should also be zero. Finish with Shutdown.

Stop the network with Ctrl+C in its terminal. Stop the Docker containers you started for this guide: maker-docs-clickhouse and, if used, maker-docs-kellnr-current7. Use docker stop <container-name> with the names you selected.

Optional maintainer checks

For a fresh SDK acceptance run, use make maker-onboarding-smoke. It can check both SDK languages across both fixture markets. Run it separately from the manual environment above. For dashboard automation, see the browser regression guide.

Optional local SDK registry

Set up a local package registry

Use this section for SDK-token issuance tests or cached package installs. Prepare it before starting the network.

Start the registry

Use Python 3.11+. First, build the Rust example to cache its SDK 7.0.4 packages. The helper reads the archives from ~/.cargo/registry/cache. If you use another Cargo home, pass its cache path with --crate-cache.

Clone the SDK source in a separate directory:

git clone --branch maker-onboarding-docs https://github.com/superis-labs/flint-api-client.git
cd flint-api-client

Then run the helper:

python3 scripts/local_maker_registry.py \
  --state .tmp/maker-registry-current7 \
  --version 7.0.4 \
  --program-id 4MxEr7W5f9xtajcTTpTTd5wfdBmwrF72j2NMg6YzXgMo \
  --port 18081 --container maker-docs-kellnr-current7

The helper starts Kellnr 6.3.0 on loopback. Its reader can download packages but cannot publish. It prints a report and saves it to .tmp/maker-registry-current7/report.json.

Build from the registry

Open the report and copy maker_cargo_home. From the Rust example directory, use that path to fetch the packages from the local registry, then build offline. This preserves the package lockfile and checksums:

CARGO_HOME='<report-cargo-home-path>' cargo fetch --locked
CARGO_HOME='<report-cargo-home-path>' cargo build --locked --offline

Enable local token issuance

Find the path in the report's gateway_env_file field. Replace <report-gateway-env-path> below with that path. Before starting the network, run these commands in the server terminal:

set -a
. <report-gateway-env-path>
set +a

Keep these local credentials in ignored .tmp and use only loopback URLs.