SOLSCOPE docs
v1.0.0
Live demo Get help
● Start · About 30 minutes

Installation
your RPC, your keys, your config.

The full setup, in order: build the app, add your own credentials, publish your admin config and turn on your fee. Every step can be done without editing source code.

01Build it

  1. Install packages
    flutter pub get
  2. Verify the project
    flutter analyze      # expect: No issues found!
    flutter test         # expect: All tests passed! (509 tests at the time of writing)
  3. Run it
    flutter run -d chrome          # or -d <device> for a phone or simulator
Windows, macOS and Linux

The flutter commands on this page are the same on every system. Lines that end in \ continue on the next line in the macOS and Linux terminals; in Windows PowerShell put the whole command on one line (or end each line with a backtick `). Commands such as cp are macOS/Linux: on Windows use Git Bash or WSL, or the PowerShell equivalent (Copy-Item .env.example .env). iOS builds need a Mac.

The tests that matter most to an operator: test/jupiter_fee_wiring_test.dart (your fee reaches Jupiter in both halves, and a fee-free build sends neither), test/swap_preview_test.dart (the fee is visible before signing) and test/pnl_test.dart (PnL is net of fees and slippage actually paid).

02Your operator console (passcode)

In plain words: the Setup tab is your control panel — it sets your fee, your data sources and keys, which parts of the app are open, and maintenance mode. Values typed there outrank your published config on that device. So it is not part of the app your users get unless you put it there, with a passcode you choose:

flutter run -d chrome \
  --dart-define=SOLSCOPE_OPERATOR_PASSCODE=<six characters or more>
  • A build without SOLSCOPE_OPERATOR_PASSCODE has no Setup tab at all — no menu entry, no bottom-nav item, no route. Ship that build to your users; it runs on your published config, your build defines and the shipped defaults.
  • A build with it lists Setup and opens it only after the passcode is typed. The unlock lasts until the app is closed and is never saved to disk. Three wrong tries pause the field for a few seconds, longer each time.
  • Fewer than six characters counts as no passcode. Forgotten it? It cannot be read back out of the app: rebuild with a new one.
  • The passcode keeps users out of your panel. It does not protect funds — nothing in the console can move any; the user's own wallet signs every swap.

03Add your credentials

There are two ways. Either works; a value set at build time wins and cannot be edited in the app.

In the app — Setup → Data sources (a build with your passcode)

Paste the value. On Android, iOS and macOS it is written to the platform keystore (flutter_secure_storage) and never shown again: the screen reports Set or Not set, never the value. On macOS that is the login keychain, which needs no Keychain Sharing capability or development team, so the in-app wallet and these values also work in an unsigned debug build (flutter run -d macos). A browser has no keystore, so in a web build the value stays in that browser's storage — for the web, prefer build defines and keys you would publish anyway.

At build time

flutter build web --release \
  --dart-define=SOLSCOPE_RPC_URL=https://<your-rpc-endpoint> \
  --dart-define=SOLSCOPE_HELIUS_API_KEY=<your-helius-key> \
  --dart-define=SOLSCOPE_COINGECKO_DEMO_KEY=<your-coingecko-key> \
  --dart-define=SOLSCOPE_ADMIN_CONFIG_URL=https://<your-host>/solscope.json

Or keep the values in a file: copy .env.example to .env, fill it in, and pass the file. .env is already in .gitignore.

cp .env.example .env
flutter build web --release --dart-define-from-file=.env
Build-time values are public on the web

A --dart-define is compiled into main.dart.js and anyone can read it. Do not put a Helius key into a public web build; use an origin-restricted endpoint, or enter keys in Setup on a phone you control. The full list of settings is in Configuration.

Setup screen, Data sources section: Helius API key, Solana RPC URL and CoinGecko Demo key not set, each field write-only and read-only in the demo
Setup → Data sources. A stored key is never echoed back; the screen reports Set or Not set, and a value pinned with --dart-define cannot be edited here.

04Set your own RPC

Before launch Without SOLSCOPE_RPC_URL the app falls back to a public endpoint, which is rate limited and not meant for production traffic. On the web, api.mainnet-beta.solana.com refuses any request that carries an Origin header (HTTP 403), so it cannot be used from a browser at all; a web build therefore falls back to https://solana-rpc.publicnode.com only (lib/core/solana/solana_rpc_service.dart).

Free public endpoints refuse the indexed calls getTokenLargestAccounts and getTokenSupply. SOLSCOPE does not send a request it knows will be refused: the token page shows which figure is missing and what unlocks it. An RPC that serves indexed reads restores the top-holder list.

Check the result in Setup → Data sources → What is answering right now: Active RPC and Indexed reads (Served / Refused).

05Publish your admin config (optional)

If you run more than one install, host one JSON file anywhere — a static file, a Worker, a Firebase Remote Config export — and point SOLSCOPE_ADMIN_CONFIG_URL (or Setup → Config source) at it. The file format is in Configuration → Admin JSON.

  1. Configure one install by handUse the Setup tab of a build with your passcode (Operator console).
  2. Copy your settingsSetup → Effective configuration → Copy as JSON gives you exactly the document to serve.
  3. Host it over HTTPSRequired: the app refuses a plain-http config URL. Save it as, for example, solscope.json on your host.
  4. Point the app at itBuild with --dart-define=SOLSCOPE_ADMIN_CONFIG_URL=https://<your-host>/solscope.json.

With no config URL the app runs on its shipped defaults and charges no fee. A failed fetch keeps the last good config instead of switching anything on.

06Turn on your fee

The fee needs two values that travel together: a rate and a token account. Read Setting up earnings → The fee account before you fill it; a plain wallet address is accepted by the form and rejected by Jupiter.

{
  "fee_bps": 25,
  "fee_account": "<your Jupiter fee token account>"
}

Setup → What this terminal earns shows Earning only when the rate and the account are both valid.

07Change the identity

Before you publish anything, give the app your own name, bundle ID, icon and deep-link scheme. The checklist is in Rebranding.