Bot Configurations
The complete SolanaMevBot 2.0.0 configuration reference
Version 2.0.0 uses [bot], one or both settlement profiles under [auto], and a repeated [[senders]] entry for each sending service. [auto_rebalance] and [log] are optional.
Unknown config fields are rejected. Start from a 2.0.0 example instead of carrying forward a 1.x config.
Bot
[bot]
rpc_url = "https://YOUR_READ_RPC"
encrypted_key_path = "~/keys/ENCRYPTED_PRIVATE_KEY"
flashloan = true| Field | Default | Meaning |
|---|---|---|
rpc_url | Required | Solana RPC for account reads and blockhashes. Must support reads, not just transaction submission. |
flashloan | false | Enable borrowing from the executor's settlement loan vault. The wallet still pays fees, tips, and account creation. |
encrypted_key_path | Automatic search | Path to an existing bot key file. Supports ~/, absolute paths, and paths relative to the working directory. Without it, the bot searches for ENCRYPTED_PRIVATE_KEY in the working directory and its parents. |
private_key | Unset | First-run key import: a base58 string or a JSON byte array encoded as a string. The bot writes ENCRYPTED_PRIVATE_KEY and exits. Remove this field before restarting. Do not combine it with an existing key file. |
See Getting Started for first-run key setup.
Automatic market selection
Configure [auto.sol], [auto.usdc], or both. Each profile selects routes that start and end in its settlement token. The SOL profile settles in wrapped SOL (WSOL).
[auto.sol]
min_total_profit = 5_000_000
min_tx_count = 2
lookback_secs = 3_600
max_routes = 50
process_delay = 50
[auto.usdc]
min_total_profit = 750_000
min_tx_count = 2
lookback_secs = 3_600
max_routes = 25
process_delay = 50| Field | Default | Meaning |
|---|---|---|
min_total_profit | Required per profile | Combined profit the feed observed through a route during lookback_secs. Integer lamports for SOL; integer millionths of USDC for USDC. |
min_tx_count | 1 | Minimum observed transaction count. Integer from 1 to 9_007_199_254_740_991. |
lookback_secs | 300 | Observation window in seconds, from 1 to 3600. |
max_routes | 50 | Maximum selected routes for this settlement, from 1 to 100. |
process_delay | 0 | Milliseconds each route waits between send passes. 0 adds no timed delay. |
For example, 5_000_000 is 0.005 SOL in [auto.sol], while 750_000 is 0.75 USDC in [auto.usdc]. These are historical selection thresholds, not per-trade profit requirements. The program checks current pool state when a transaction executes.
Each route runs independently. process_delay is not a global requests-per-second limit; use each sender's rate_limit_per_second, or from 2.0.4 each key's, to cap submissions across all routes and both settlements.
Senders
Add at least one enabled sender to submit transactions. Each sender builds transactions using its own prices and tips.
[[senders]]
name = "rpc"
type = "json_rpc"
urls = ["https://YOUR_SENDING_RPC"]
rate_limit_per_second = 20
compute_unit_price = { strategy = "Random", from = 1000, to = 2000, count = 1 }
request_params = { maxRetries = 10 }Sender types and defaults
type | Request format | Default submissions/second | Default timeout | Default strategy |
|---|---|---|---|---|
json_rpc | JSON-RPC sendTransaction | 20 | 1500 ms | AllAtOnce |
jito | JSON-RPC sendBundle, appending /bundles to each URL; from 2.0.4, also gRPC to a key's grpc_urls | 1 | 5000 ms | OneByOne |
send_bundle | JSON-RPC sendBundle to the exact URL | No configured cap | 5000 ms | AllAtOnce |
submit_batch | A transactions array of base64 transactions | No configured cap | 5000 ms | AllAtOnce |
next_block | A transaction object with base64 content | No configured cap | 5000 ms | AllAtOnce |
harmonic | Harmonic bundles over gRPC (2.0.2 or later) | No configured cap | 5000 ms | OneByOne |
temporal | Nozomi sendBundle, posting each transaction's bytes after its length to the URL's /api/sendBundle (2.0.4 or later) | 5 | 5000 ms | AllAtOnce |
type is required. For jito, supply a block-engine URL ending in /api/v1, not /api/v1/bundles; a key's grpc_urls take the block engine without a path, such as https://ny.mainnet.block-engine.jito.wtf (see Jito with several uuids and gRPC). For harmonic, supply a regional URL such as https://fra.be.harmonic.gg; see Harmonic. For temporal, supply a regional host with your key, such as https://fra2.nozomi.temporal.xyz/?c=YOUR_API_KEY. See Temporal Nozomi bundles.
Sender fields
| Field | Default | Meaning |
|---|---|---|
name | Required | Nonempty, unique name used in logs, including for disabled senders. |
type | Required | One of the types above. |
enabled | true | Whether this sender submits transactions. |
urls | Empty | Endpoint URLs. Required for an enabled sender unless using keys. |
auth_header, auth_value | Unset | HTTP authentication header and value. Set both together. Not accepted by harmonic. |
keys | Empty | Endpoint groups with separate credentials and, from 2.0.4, their own rate limits; see below. Not accepted by harmonic. |
request_params | Unset | Table merged into JSON-RPC request options. Supported by json_rpc, jito, and send_bundle only. |
sending_strategy | By type | AllAtOnce sends to every endpoint. OneByOne rotates the starting endpoint and tries another on connection failures, timeouts, HTTP server errors (5xx), or gRPC errors other than a rejection or rate limit. Acceptance or rejection ends the submission, and a rate-limit response stops it trying further endpoints. From 2.0.4, keys with their own rate limit are separate lanes: AllAtOnce sends through every lane that has room, and OneByOne moves on to another lane with room when every endpoint of its lane is unreachable or the lane is rate limited. |
compute_unit_price | Unset | Priority price strategy in micro-lamports per CU. Unset means no added priority fee. Required for harmonic, at least 10000. |
tip_amount | Unset | Tip strategy in lamports. Required for jito and temporal. Not accepted by harmonic, which is paid through compute_unit_price. |
tip_accounts | Empty | Tip destination public keys. Required with a tip for other senders. jito and temporal (2.0.4 or later) use their built-in accounts when omitted. |
rate_limit_per_second | By type | Integer from 1 to 1000. Shared across all routes, settlement profiles, and source IPs for this sender. From 2.0.4, a key can set its own; keys that don't share the sender's. |
timeout_ms | By type | Positive request timeout in milliseconds. |
no_failure_mode | false | Allow the executor to return without a trade when no profitable route is found. Does not suppress every possible transaction error. |
uuid | Unset | Jito-only uuid query parameter. A key's own uuid (2.0.4 or later) replaces it for that key. |
auth_keypair | Unset | Path to the keypair file of a public key Harmonic whitelisted. Without it, bundles go to Harmonic's public service. Accepted on the sender by harmonic only; from 2.0.4, a Jito key with grpc_urls can set its own to sign in to Jito. |
ip_addresses | Empty | Local source IPs or CIDR ranges. Submissions rotate through them. These addresses must be configured on your machine. HTTP only: not accepted by harmonic, and Jito gRPC keys connect from the default address. |
use_separate_tip_account | On for Jito with ip_addresses; otherwise off | Jito-only: use a temporary tip account and a second transaction in the bundle to forward the tip. Requires tip_amount. |
A rate limit counts submissions, not requests. A submission counts once against each lane it goes through, including a lane it moves on to. With AllAtOnce, a submission goes to every endpoint of its lanes, so the number of HTTP requests can be higher.
JSON-RPC transaction options default to encoding = "base64", skipPreflight = true, preflightCommitment = "confirmed", and maxRetries = 10. Bundle options default to encoding = "base64". request_params overrides matching options. Keep base64 encoding, since that is how the bot serializes transactions.
Multiple credentials
Use [[senders.keys]] when one sender has multiple endpoint groups with different credentials. Each group supports urls, auth_header, auth_value, and request_params. From 2.0.4, a group can also set rate_limit_per_second, and a Jito group can set uuid, or list grpc_urls with an optional auth_keypair instead of urls.
[[senders]]
name = "rpc-keys"
type = "json_rpc"
rate_limit_per_second = 10
sending_strategy = "OneByOne"
request_params = { maxRetries = 0 }
[[senders.keys]]
urls = ["https://YOUR_FIRST_RPC"]
auth_header = "authorization"
auth_value = "YOUR_FIRST_API_KEY"
[[senders.keys]]
urls = ["https://YOUR_SECOND_RPC"]
auth_header = "authorization"
auth_value = "YOUR_SECOND_API_KEY"When using keys, omit sender-level urls, auth_header, and auth_value. A key's request_params replaces the sender-level table for that key; the chosen table is then merged into the request defaults.
Rate limits per key
Requires bot 2.0.4 or later. A key that sets rate_limit_per_second gets a limit of its own, apart from the sender's and other keys'. Keys that set none share the sender's limit. If every key sets its own, leave the sender's rate_limit_per_second unset; the bot rejects a sender limit that would apply to no key.
Each limit is a lane. OneByOne sends each submission through the next lane that has room, and moves on to another lane that has room when every endpoint of its lane is unreachable or the lane is rate limited. AllAtOnce sends through every lane that has room. A rate-limit reply pauses only its lane, for two seconds. With OneByOne, the sender can send up to the sum of its lanes' limits. Logs name the shared lane by the sender's name, and a key with its own limit by the sender's name and the key's position counting from 0, such as jito keys[1] for the second key of a sender named jito. See Jito with several uuids and gRPC for an example.
Tips and no-failure mode
With no_failure_mode = false, a transaction must profit at least its tip. For jito, send_bundle, and harmonic from 2.0.3, and temporal from 2.0.4, whose bundles do not land when they revert, it must also cover the bundle's fees: the signature fee, the priority fee, and the tip forwarder's transaction if there is one. For other senders the floor does not cover transaction fees. For USDC settlement, the bot converts the floor into USDC with a 20% margin.
With no_failure_mode = true, the bot removes that profit floor. A transaction may succeed without a trade and still pay its tip and network fees. This setting does not make submissions free or guarantee a profit.
Astralane endpoints without a supplied API key use the bot's shared default key and require no_failure_mode = true. Use an api_key header or an api-key/api_key URL query parameter to supply your own key.
See Sending Vendor Examples for service-specific setups.
Price and tip strategies
compute_unit_price and tip_amount use the same strategy structure, except Helius is supported only for compute unit prices. Strategy names are case-sensitive.
| Strategy | Fields | Behavior |
|---|---|---|
Random | from, to, count | Uniform random integers in the inclusive range. Set from equal to to for a fixed value. |
ExponentialRandom | from, to, count | Random values distributed on a logarithmic scale. Use positive from below to. |
Linear | from, to, count | Values spaced with an integer step across the range. One value uses from. |
Exponential | from, to, count | Values spaced geometrically across the range. from must be at least 1. |
File | file_path | Read integer values, one per line. Blank lines and # or // comments are ignored. The file is reread each send pass. |
Helius | api_key; optional fields below | Scale the Helius priority fee estimate for the transaction's accounts. |
For the four range strategies, provide count of at least 1 and from no greater than to (ExponentialRandom requires a strict increase). An optional min sets a lower bound on generated values for non-Helius strategies. max applies only to Helius.
Each send pass tries the combinations of generated tip amounts and compute unit prices, subject to the sender's rate limits. For example, two tips and three prices produce six candidate submissions per basket.
Helius priority prices
[[senders]]
name = "rpc-helius-prices"
type = "json_rpc"
urls = ["https://YOUR_SENDING_RPC"]
compute_unit_price = { strategy = "Helius", api_key = "YOUR_HELIUS_API_KEY", from = 90, to = 130, count = 3, max = 20000, fetch_interval = 5 }Here from and to are percentages of the estimate, not micro-lamport amounts. This example generates three prices from 90% to 130% of the estimate, capped at 20,000 micro-lamports per CU.
| Helius field | Default | Meaning |
|---|---|---|
api_key | Required | Helius API key used for priority fee estimates. |
from | 100 | Starting percentage of the estimate. |
to | Same as from | Ending percentage. |
count | 1 | Number of generated prices; values below 1 are treated as 1. |
max | Unset | Upper bound in micro-lamports per CU. |
fetch_interval | 5 | Cache interval in seconds, with a minimum of 1. |
account_keys | Empty | Additional account addresses to include with the transaction's accounts when requesting an estimate. |
Auto-rebalance
This optional section checks the wallet every minute. When native SOL falls below min_sol_balance, the bot unwraps WSOL and wraps min_wsol_balance again. It skips rebalancing if the combined SOL and WSOL balance is below the two configured amounts added together.
[auto_rebalance]
min_sol_balance = 500_000_000
min_wsol_balance = 200_000_000
compute_unit_price = 10_000All three fields are required when this section is present. Balances are in lamports; compute_unit_price is in micro-lamports per CU. Rebalancing does not sell USDC, and it is not an initial funding mechanism for the WSOL account.
Logging
[log]
enable_sending_log_summary = true
summary_interval_seconds = 60enable_sending_log_summary defaults to false. When enabled, periodic summaries replace the per-transaction logs of successful sends; failed sends are still logged, except replies that the transaction was already processed. summary_interval_seconds defaults to 60.
Applying config changes
The bot checks the config file every second. Sender settings and filters for the existing settlement profiles can update while it runs. Invalid edits keep the previous config active.
Restart after adding or removing a settlement profile, changing the RPC or wallet, or changing auto-rebalance settings. These changes take effect on the next start.
Removed 1.x settings
| Previous setting | 2.0.0 replacement |
|---|---|
[rpc] | bot.rpc_url |
[wallet] | bot.private_key for first import, then bot.encrypted_key_path |
[flashloan].enabled | bot.flashloan |
[spam], [jito], [[sending_venders.sending_vender]] | [[senders]] with an explicit type |
request_format, enable_submit_batch | Sender type = "send_bundle" or "submit_batch" |
| Manual mint/pool lists and bundle groups | [auto.sol] and/or [auto.usdc] |
| Manual compute limits, transaction-version selection, and lookup table configuration | Managed by the bot |
Remove old fields rather than leaving them alongside the new ones: unknown fields prevent the config from loading.