Skip to content

Onchain Solana First Trade

Use this tutorial to make a small Onchain Solana trade from the CLI. It starts with read-only Solana checks, uses preview before live submission, and ends with post-trade reconciliation.

Onchain (Solana) trading is experimental. Keep first trades small and use explicit mint addresses.

Prerequisites

Update the CLI, sign in, and enable the Solana command group:

bullpen upgrade
bullpen login
bullpen status --output json
bullpen experimental enable solana

Fund your Bullpen-managed Solana wallet through the web app deposit flow:

bullpen solana deposit

After the deposit settles, refresh balances:

bullpen solana balance --refresh --output json
Example refreshed balance output
{
  "address": "7qRk...u1G8e",
  "sol_balance": "0.42",
  "total_usd": "125.55",
  "tokens": [
    {
      "mint": "EPjF...Dt1v",
      "symbol": "USDC",
      "amount_ui": "125.55",
      "value_usd": "125.55"
    }
  ]
}

Find a Token

Search by symbol or name, then inspect the exact mint:

bullpen solana search WIF --output json
bullpen solana token <MINT> --output json
bullpen solana price <MINT> --output json

Use the mint address from search output. Do not use a ticker alone for buy, sell, swap, withdraw, limit-order, or DCA commands.

Check Token Risk

Review token risk before previewing a buy:

bullpen solana token risk <MINT> --output json

Continue only when the risk warnings, holder concentration, developer context, and token metadata match your tolerance. Treat missing risk fields as incomplete evidence, not as a clean bill of health.

Money-moving Solana commands require base58 SPL token mint addresses. Use bullpen solana search <SYMBOL> for discovery, then pass the returned mint to buy, sell, swap, limit-buy, limit-sell, or dca create; symbols such as BONK are not accepted as trade inputs.

Preview the Buy

Preview returns a Jupiter Ultra quote without signing or submitting a transaction:

bullpen solana buy <MINT> 5 --preview --output json

Review the input amount, output amount, route, price impact, slippage, fees, and any shield warnings.

Example buy preview output
{
  "action": "buy",
  "input_mint": "EPjF...Dt1v",
  "input_symbol": "USDC",
  "input_amount": "5",
  "output_mint": "<MINT>",
  "output_symbol": "TOKEN",
  "output_amount": "1234.56",
  "price_impact_pct": "0.18",
  "slippage_bps": 50,
  "would_submit": false,
  "warning": null
}

Default slippage is 50 bps. Use --slippage-bps only when you have reviewed the route and price impact.

Submit the Buy

Run the live command only after the preview matches your intent:

bullpen solana buy <MINT> 5 --yes --output json

The live path signs with the Bullpen-managed Turnkey Solana signer and submits through Bullpen transaction services. If the command reports an auth or signing-session error, run bullpen status --output json and bullpen doctor auth --output json; run bullpen login only when diagnostics or the failed command says login is required. Then rerun the same preview before submitting again.

Example live buy output shape
{
  "kind": "solana_swap_result",
  "success": true,
  "status": "confirmed",
  "signature": "5Zk...abc",
  "tx_signature": "5Zk...abc",
  "readback_status": "confirmed",
  "receipt_status": "confirmed",
  "input_mint": "EPjF...Dt1v",
  "input_symbol": "USDC",
  "input_amount": "5",
  "output_mint": "<MINT>",
  "output_symbol": "TOKEN",
  "output_amount": "1234.56",
  "input": {
    "mint": "EPjF...Dt1v",
    "symbol": "USDC",
    "amount": "5"
  },
  "output": {
    "mint": "<MINT>",
    "symbol": "TOKEN",
    "amount": "1234.56"
  },
  "slot": 341234567
}

Reconcile After Submission

Refresh balances and inspect recent activity:

bullpen solana balance --refresh --output json
bullpen solana history --limit 10 --output json
bullpen solana orders --output json

balance --refresh is the preferred post-trade check because it requests a portfolio refresh and overlays fresh on-chain SOL and SPL-token balances when a Solana RPC source is available. JSON output includes freshness.status, freshness.source, freshness.on_chain_proven, freshness.checked_at_ms, and freshness.warning.

Treat freshness.status: "fresh" with on_chain_proven: true as the strongest post-fill proof. If the CLI returns pending_indexer_refresh, the command kept the portfolio cache and attached a warning because it could not prove the latest on-chain state through RPC. Wait briefly and run the refresh again before submitting another live buy or declaring cleanup failed.

When a live swap report returns success: true, the transaction landed even if readback_status is readback_pending or readback_failed. If you need to sell the received token immediately, run:

bullpen solana history --type trades --limit 10 --output json

Match the live report signature against entries[].signature, then use the matching received.amount for the cleanup sell. Do not size cleanup from a stale balance snapshot.

Sell or Swap Back

Preview the exit first:

bullpen solana sell <MINT> <TOKEN_AMOUNT> --preview --output json
bullpen solana swap <MINT> EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v <TOKEN_AMOUNT> --preview --output json

Submit only after reviewing the route:

bullpen solana sell <MINT> <TOKEN_AMOUNT> --yes --retry-after-rate-limit --output json

--retry-after-rate-limit waits for Jupiter's returned cooldown and retries once when the first live submit was rate-limited before a transaction signature existed. It does not replay a transaction after a signature or receipt exists. If the sell succeeds but leaves only sub-cent residual token dust, the live JSON report includes post_swap_dust; leave that dust alone unless the balance grows enough for a normal sell route.

Native SOL as the input side of a live sell or swap may require a Jupiter auxiliary signature that Bullpen cannot provide. If the CLI returns SOLANA_SWAP_UNSUPPORTED_ROUTE, use an SPL-token input route or retry with a USDC-to-token flow.

Preview Limit Orders

Use a limit order when you want Jupiter Trigger to buy or sell only at a target price. Preview first; the preview builds the request without signing or submitting. Jupiter Trigger requires at least about $5 per limit order. The examples below use the minimum valid size; smaller orders return SOLANA_TRIGGER_ORDER_TOO_SMALL before signing or provider submission.

bullpen solana limit-buy <MINT> 5 --price <USD> --preview --output json
bullpen solana orders --status active --output json
bullpen solana cancel-order <ORDER_KEY> --preview --output json

Submit or cancel only after you review the preview:

bullpen solana limit-buy <MINT> 5 --price <USD> --yes --output json
bullpen solana cancel-order <ORDER_KEY> --yes --output json

orders is read-only. Use the order key returned by orders or by the live create response; do not invent one from the token mint. Live limit-order JSON results expose kind, success, status, order_key, signature, and the compatibility aliases order and tx_signature. After a live cancel, run bullpen solana balance --refresh --output json before relying on returned funds.

Preview DCA

Use DCA when you want Jupiter Recurring to split a USDC-to-token buy over time. --per-cycle is in input-token units. For USDC input, --per-cycle 50 means 50 USDC per cycle. --cycles must be between 2 and 1000; invalid cycle counts return SOLANA_DCA_INVALID_CYCLES before Jupiter is called.

bullpen solana dca create EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v <MINT> --per-cycle 50 --cycles 4 --interval 1d --preview --output json
bullpen solana dca list --status active --output json
bullpen solana dca cancel <ORDER_KEY> --preview --output json

Jupiter Recurring enforces provider-side minimums. If the CLI reports SOLANA_DCA_MINIMUM_PER_CYCLE, increase --per-cycle or use a normal preview buy instead.

After a live DCA create, inspect index_status in JSON output. If the schedule is still indexing, the CLI returns index_status: "index_timeout" on create or SOLANA_DCA_INDEX_PENDING on cancel with retry_after_secs and next_command. Wait before retrying and run bullpen solana dca list --all --output json before creating another schedule. Live DCA JSON results expose kind, success, status, order_key, signature, and tx_signature. After a live cancel, run bullpen solana balance --refresh --output json before relying on returned funds.

Troubleshooting

Symptom What to run
Solana command is hidden bullpen experimental enable solana
Balance looks stale bullpen solana balance --refresh --output json
Jupiter rate limited the route Read next_command_after, wait for retry_after_secs, rerun preview, then retry the same live command only if the preview is still acceptable. Use --retry-after-rate-limit for unattended cleanup after a confirmed buy or swap.
Signing session expired Run bullpen status --output json and bullpen doctor auth --output json; run bullpen login only when diagnostics or the failed command requires login
Token ticker is ambiguous bullpen solana search <QUERY> --output json and use the mint
Live route is unsupported Use an SPL-token route or a USDC-to-token buy

See Onchain (Solana) for the full command surface and current limitations.

Use generated references for exact flags: buy, sell, swap, history, limit-buy, orders, cancel-order, dca create, dca list, dca cancel, token risk, token hide, and token unhide.