Skip to content

Onboarding

Getting setup to quote on Flint

Audience

This page assumes you're either:

  • Building a market-maker bot. You'll quote on at least one pair and need a maker_id registered against your pubkey.
  • Building a read-only integration (analytics, charts, alerts). Public market data, aggregate stats, and historical backfills need no auth.

1. Get an endpoint

The server binds two gRPC listeners so operators can front each with a different ingress policy (public CDN/cache vs. mTLS / authenticated edge):

ListenerDefault portServicesAuth
Public50051MarketDataService, StatsService, HistoricalService, AuthServiceNone — public.
Authed50052AuthService, MakerService, TxServiceBearer session token for all except AuthService.

AuthService is available on both listeners. The public listener is enough for login flows; makers also configure the authed listener because the tokens it mints are used by MakerService and TxService.

EnvironmentPublicAuthed
Mainnethttps://api.superis.exchange:443https://auth.api.superis.exchange:443
Testnethttps://testnet.api.superis.exchange:443https://auth.testnet.api.superis.exchange:443
Localhosthttp://localhost:50051http://localhost:50052

(SUPERIS_INSECURE=1 tells the SDKs to skip TLS for local hosts.)

Market-data, stats, historical, and browser login integrations only need the public endpoint. Makers need the authed endpoint too.

2. Solana wallet

You need an Solana keypair. The same key:

  1. Authenticates with the gRPC server (signs the AuthService challenge).
  2. Signs on-chain quoting transactions (UpdateOracleFair, UpdateQuotingParams).

The server only accepts authenticated calls from pubkeys that are registered as quoting authorities for some maker_id.

3. Register your pubkey as a quoting authority

If you don't already have a maker_id, the on-chain admin needs to create one for you. Maker creation is a one-time CreateMaker instruction signed by the admin; ask the operator that runs your deployment.

If you already have a maker_id and want to delegate quoting to a hot wallet, send a ManageMaker { AddQuoter } instruction to the Flint program from the maker admin wallet, naming the hot wallet as the new quoter.

Hot vs. cold wallets

Use a cold wallet to mint your maker_id and set max_balance / risk params (the admin path). Use a delegated hot wallet for the high-frequency UpdateOracleFair / UpdateQuotingParams flow.

4. Fund the maker

Flint allocates liquidity dynamically at swap time — not when you publish a quote. When a taker hits your book, the matcher reads your current balance and caps the fill against:

  • on the sell side of the fill (the token going out of your account): available_to_sell = your deposited balance of that token.
  • on the buy side of the fill (the token coming in): available_to_buy = soft_max_balance − balance — the headroom under your cap.

Because the check happens at swap time, two properties fall out that surprise people coming from a CEX:

  1. You can publish levels larger than what you currently hold. Quotes aren't rejected on size. The matcher fills up to whatever budget exists at the moment of the swap. A 10 SOL ask with 5 SOL deposited fills 5 SOL.

  2. Fills feed adjacent quotes. A SOL ask that pays out SOL brings USDC in. That USDC immediately becomes available_to_sell USDC backing any SOL bid you also posted — the bid can then fill on the very next swap. A maker can run a two-sided book on a one-sided initial deposit; inventory cycles through the quotes.

Worked examples (which balance gates which side of each fill):

Your quoteSell-side budget — depositedBuy-side budget — cap with headroom
Sell SOL on SOL/USDCSOL deposited in the SOL micro-bookUSDC soft_max_balance on the global market
Buy SOL on SOL/USDCUSDC deposited in the global marketSOL soft_max_balance on the SOL micro-book
Sell SOL on SOL/ETHSOL deposited in the SOL micro-bookETH soft_max_balance on the ETH micro-book
Buy SOL on SOL/ETHETH deposited in the ETH micro-bookSOL soft_max_balance on the SOL micro-book

The same rule explains both modes — SOL/USDC just keeps the USDC side in the singleton GlobalMarket account instead of a per-spot micro-book. Each fill is a single two-token settlement; nothing is multihop.

Two on-chain accounts hold these balances:

AccountSet byPurpose
SpotMakerMicroBook.balance (one per spot)DepositWithdraw + UpdateQuotingParams.max_balanceDeposited base + per-spot soft_max_balance cap.
GlobalMarket.balances[maker_id] (singleton)DepositWithdrawQuote + set_quote_max_balanceDeposited USDC + global soft_max_balance cap.

The silent filter

Quotes are filtered only when a side's budget reads literally zero at swap time — no deposit on the sell side, or no soft_max_balance headroom on the buy side. A fresh maker has soft_max_balance = 0 everywhere, which makes every buy-side budget 0. The classic cold-start mistake: a maker quoting SOL/USDC with deposited SOL but no soft_max_balance set on the USDC (global) side — sells go up, never fill because the buy-side USDC budget is 0.

5. Install an SDK

sh
cargo add sweetspot-api-client tokio --features tokio/macros,tokio/rt-multi-thread
sh
npm install @superis-labs/sweetspot-client @bufbuild/protobuf
sh
pip install flint-sdk
# from a checkout:
pip install -e './python[dev]'
make py-gen

6. First authenticated call

rust
use std::sync::Arc;
use sweetspot_api_client::api::client::Client;

let client = Client::builder()
    .public_endpoint("https://api.superis.exchange:443")
    .auth_endpoint("https://auth.api.superis.exchange:443")
    .wallet(Arc::new(my_keypair))
    .build()
    .await?;

let session = client.authenticate().await?;
println!("authenticated as maker_id={}", session.maker_id);

If Client::authenticate() returns UNAUTHENTICATED: pubkey not registered as a quoting authority, your pubkey hasn't been added yet — go back to step 3.

7. Verify the program id

Defense in depth. The RPC check confirms the advertised account exists, is executable, and is owned by a Solana BPF loader. To prove it is the Flint program you intended to trade against, compare it with a program id from trusted configuration as well.

rust
use sweetspot_api_client::api::config::verify_program_id;

let cfg = client.refresh_config(None).await?;
verify_program_id("https://api.mainnet-beta.solana.com", &cfg.program_id).await?;

Run this once at boot; if either the executable-account check or your trusted program-id comparison fails, refuse to quote until it passes.

8. Pick your path

GoalNext page
Stream books and fillsMarket data
Quote and submit fillsQuoting
Run or fork a Python maker botsweetspot-maker-example
Pull historical trades / candlesHistorical queries
Sign-in flow detailAuth flow

Build on Solana