Setup
From a licence key to a running bot. Read the whole page once before you start — particularly Configure, where the numbers that govern real money live.
Requirements
- Node.js 18 or newer. Check with
node --version. - A Solana wallet you control, funded with SOL for trading and fees.
- Your own Solana RPC endpoint. A public RPC will rate-limit this bot almost immediately — use a provider.
- A machine that stays on. The bot only finds opportunities while it is running.
- Your BOTSOL licence key.
Install
Node.js 18+ is required for both. Windows and Linux: use the zip.
Unpack the download, then install dependencies:
Create your configuration from the supplied example:
.env holds your private key.
It is excluded from version control. Never paste its contents into a
chat, an issue tracker, a support request, or any website — including
this one.
Configure .env
Every variable the bot reads, with its real default. Defaults are taken
from the shipped .env.example.
Required
| Variable | Default | What it does |
|---|---|---|
PRIVATE_KEY |
— | Your wallet key, base58 or a JSON byte array. Used locally to sign. Never transmitted. |
RPC_URL |
— | Your Solana RPC endpoint. |
LICENSE_KEY |
— | The key from your purchase. |
Safety
| Variable | Default | What it does |
|---|---|---|
DRY_RUN |
true | Runs the complete path — detect, validate, build, sign — and stops immediately before submitting. Nothing is broadcast and no funds move. |
DRY_RUN=true until you have watched it run.
Let it operate for a while and read what it says it would have done. Set
it to false only when you agree with those decisions. This
is the single most useful safety habit with this software.
Trading
| Variable | Default | What it does |
|---|---|---|
TRADING_PAIRS |
unset |
Comma-separated SYMBOL/SYMBOL. Unset means
exactly SOL/USDC and nothing else. Known symbols: SOL,
USDC, USDT, JUP. Unknown symbols are skipped with a startup
warning, not a crash. The base leg must be SOL.
|
MAX_TRADE_SIZE_SOL |
0.1 | Size of each attempt, in SOL. |
MIN_PROFIT_THRESHOLD_PCT |
0.5 | Minimum round-trip profit, in percentage points, before a trade is considered. Computed from real quote amounts, which already net out AMM swap fees. |
POLL_INTERVAL_MS |
3000 | How often to look. Lower means more RPC and Jupiter calls — check your rate limits. |
SLIPPAGE_BPS |
50 | Slippage tolerance passed to Jupiter. 50 = 0.5%. |
MIN_PROFIT_THRESHOLD_PCT is measured from swap quotes,
which account for AMM fees but not Solana network fees,
priority fees, or Jito tips. Set it high enough to cover those, or you
can win trades on paper and still lose balance.
Pre-execution validation
These tune the re-check that runs immediately before every trade. The check itself cannot be disabled — only these numbers are configurable.
| Variable | Default | What it does |
|---|---|---|
MAX_PRICE_IMPACT_PCT |
1.0 | Maximum acceptable price impact on the worse of the two legs. Guards against thin liquidity. |
MAX_PROFIT_DEGRADATION_PCT |
0.2 | Maximum drop, in percentage points, between the profit seen at detection and at the final re-check. A larger drop blocks the trade even if profit still clears the threshold — it signals an opportunity that is closing. |
Jupiter API
| Variable | Default | What it does |
|---|---|---|
JUPITER_API_BASE |
lite-api.jup.ag/swap/v1 | Keyless free tier. Reduced rate limits, intended for testing. |
JUPITER_API_KEY |
unset | Required if you move to the production host. |
For sustained use, Jupiter's own guidance is to use
https://api.jup.ag/swap/v1 with an API key from their
developer portal. Depending on your poll interval and pair count that
may require a paid plan — a recurring cost you pay Jupiter directly, not us.
First run
On startup it prints what it is about to do. Check each line:
- Your wallet address and SOL balance — confirm it is the wallet you meant
- The pairs being watched — with
TRADING_PAIRSunset this must read exactlySOL/USDC - Any skipped pairs, with the reason
- Your thresholds
- Whether Jito is on or off
- Whether
DRY_RUNis on
SKIP mean an opportunity was found and then
rejected at the final check — the spread closed, liquidity was too thin,
or profit degraded. A long run of skips is normal and healthy. A bot
that never skips is one that is not checking.
Dashboard
While the bot runs it serves a local dashboard. Open it at:
Change the port with DASHBOARD_PORT in your
.env.
Status tab
- Whether the bot is running or paused, and a pause/resume control
- Your wallet's public address and SOL balance — never your private key
- The pairs actually being watched, plus any that were skipped and why
- Your thresholds, read-only
- Realised profit and loss for the session, labelled as such
- Skipped opportunities, grouped by reason
- A live activity log you can filter and copy for support
This tab works with no internet connection. If the bot stops sending updates the page dims and says so, rather than showing old numbers as though they were live.
Buy Licence and Builder Pro tabs
These talk to the licence server, so they need
LICENSE_SERVER_BASE_URL set. If it is not set, they say so
and name the variable. The Status tab is unaffected either way.
Jito bundle execution Optional
Off by default. When off, trades are submitted through your own RPC exactly as they otherwise would be.
| Variable | Default | What it does |
|---|---|---|
ENABLE_JITO_BUNDLES |
false | Submit each leg as a Jito bundle instead of a plain RPC transaction. |
JITO_TIP_LAMPORTS |
100000 | Tip per attempt. 100000 lamports = 0.0001 SOL. |
Tip accounts are fetched live from Jito on every submission and never hardcoded. The tip is always a separate transaction alongside the swap; the swap transaction itself is never modified.
Remote viewing Optional
Troubleshooting
PRIVATE_KEY is not set
Your .env is missing or the variable is empty. Confirm
the file is named exactly .env, sits in the same folder
as index.js, and that you copied it from
.env.example.
PRIVATE_KEY could not be parsed
The value is not a valid base58 string or JSON byte array. Re-export it from your wallet. The bot never logs the value itself, so the error will not show you what it read.
RPC_URL is not set, or constant rate-limit errors
You are on a public RPC or have none configured. Get an endpoint from a provider. This is the single most common cause of a bot that appears to do nothing.
It finds opportunities but never trades
Expected, and usually correct. Check whether DRY_RUN is
still true — in that mode it never submits. Otherwise
read the SKIP reasons: the spread closed, price impact
exceeded your limit, or profit degraded past your tolerance.
It never finds anything at all
Most likely your threshold is above what the market is offering. Real round-trip spreads on major pairs are frequently a small fraction of a percent. Lowering the threshold finds more — but remember it must still cover network fees and any tips, or the trades lose money.
A pair I configured is not being watched
Check the startup warnings. Unknown symbols, malformed entries, and pairs whose base is not SOL are all skipped with a stated reason.