Designing a Dry Run You Can Afford to Lose
A dry run is a mainnet rehearsal at a size chosen so the worst plausible outcome is an amount you have already written off. It is the first layer of testing that costs real money, and the only one that observes execution against real liquidity, so its design deserves a sheet rather than a decision made at the keyboard.
- Applies to
- Any automation about to sign mainnet transactions for the first time under a new build or configuration
- Preconditions
- Devnet flow complete, transactions simulate cleanly against mainnet, abort conditions written
- Pass condition
- The run reaches its planned end, results match the criteria, and every action maps to a signature
- Out of scope
- Any conclusion about behaviour at a size larger than the one you ran
Design a dry run by fixing four numbers before anything is signed: the amount you have written off, the number of transactions, the abort thresholds, and the evidence you will record for each attempt. Everything else in the rehearsal is real, including the fees and the liquidity, and the only variable you scale down is exposure.
What a dry run is
A dry run is a live rehearsal on mainnet, sized so that the worst plausible outcome is affordable. It is not a demonstration and not a profitability test. Its output is a set of observations about execution: what landed, what failed and why, what the fees actually were, and whether the tool's own account of the run matches what the chain recorded.
The word rehearsal is precise. An orchestra rehearses in the hall it will perform in, because the hall is part of what it is learning. A trading rehearsal happens on the network the system will run on, for the same reason: the network is not a detail of the environment, it is the thing that produces most of the interesting failures.
The discipline that makes a rehearsal different from just switching the bot on is that expectations are written first. Before each class of transaction, you record what you expect to observe. Afterwards you record what you observed. The gap between them is the finding, and without the first half there is no gap, only a story.
Paper trading against a live test
Paper trading is a useful test of one component and a misleading test of the system. It exercises the decision logic against price data and stops there. Nothing in it can fail the way real execution fails, because there is no transaction, no blockhash, no compute budget, no account that needs creating and no other participant competing for the same block space.
| Question | Paper trading | Sized dry run |
|---|---|---|
| Does the strategy logic produce the intended decisions? | Yes | Yes, incidentally |
| Does a decision become a signed transaction? | No | Yes |
| Does the transaction land, and how often? | No | Yes, at the size and time you ran |
| What does execution actually cost? | Estimated at best | Measured from balance changes |
| How does it behave when a dependency fails? | Not applicable | Yes, if it happens or you inject it |
| Is there an evidence trail you can audit? | Internal only | Signatures on a public ledger |
| How does it behave at production size? | No | No |
The last row is shared, and it is the honest limit of both. Neither method tells you about a size you did not run. This is why scaling after a successful rehearsal is a decision that needs its own reasoning rather than an assumption that the result carries.
Sizing the rehearsal
Size the run from the loss you have accepted, not from the result you want. Start by writing the number you are prepared to spend on information, then divide it into the components that will consume it: transaction fees, any rent deposits for accounts that must be created, the venue's own trading fee, and the price impact of your own trades.
The arithmetic below is illustrative and uses protocol constants plus a stated assumption; it describes no real run. Suppose the rehearsal is forty swaps of 0.1 SOL, giving 4 SOL of turnover. At a base fee of 5,000 lamports per signature plus a priority fee of 10,000 lamports per transaction, fees are 40 multiplied by 15,000 lamports, which is 600,000 lamports, or 0.0006 SOL.
Assume the pool charges a trading fee of 0.25 percent per swap. On 4 SOL of turnover that is 0.01 SOL. Creating two associated token accounts costs a rent-exempt deposit of 0.00203928 SOL each, which is recoverable if the accounts are later closed. So the non-recoverable cost before price impact is roughly 0.0106 SOL, and price impact is the number the rehearsal exists to measure rather than to assume.
Why the fee assumption has to be stated
Both the priority fee and the pool fee in that example are assumptions, not constants. Priority fees move with demand for block space, and different pool types charge different fee tiers. The arithmetic is still worth doing before the run, because the comparison between predicted and actual cost is one of the most informative outputs of a rehearsal, and it is only possible if the prediction was written down first.
The dry run design sheet
One page, filled in before the first transaction. If a line cannot be completed, the run is not ready.
DRY RUN DR-003
BUILD 3f2a1c / config-rehearsal.json
VENUE Named market and pool address
WALLET SET Public keys, funded amounts, source of funds
WRITTEN OFF Total amount treated as spent before the run begins
TRANSACTIONS Planned count and per-transaction size
PREDICTED COST Fee estimate + rent deposits + expected venue fee
CRITERIA AC ids this run is evidence for
RECORD PER TX Signature, slot, expected, observed, verdict, note
ABORT Written thresholds, each with a number
STOP CONDITION The event or count that ends a successful run
OWNER Person watching the run and able to stop it
EVIDENCE FILE Path where the record is written, UTC timestamps The two lines people skip are OWNER and STOP CONDITION. An unattended first rehearsal has no one to invoke the abort conditions, which makes the abort conditions decorative. And a run with no defined ending tends to continue while it is going well, which converts a test into a position.
The cost model
Execution cost has four components and they behave differently. Network fees are small, predictable and per-transaction. Rent deposits are one-off and recoverable. Venue fees scale with turnover. Price impact scales with size relative to available depth, which means it is the only one that grows non-linearly as you scale the run up.
That last property is why a rehearsal's cost per unit of turnover is a lower bound rather than a forecast. Ten times the size does not cost ten times as much; it costs more, by an amount that depends on depth at the moment you trade. Any model that assumes linearity will underestimate exactly when it matters.
Where the tool is a paid service rather than your own code, the vendor's own charge is a fifth component and belongs in the same table. It is worth working through how Solana volume bot cost is normally structured across the category before writing the criterion, because a per-transaction charge, a percentage of turnover and a flat subscription produce completely different arithmetic at rehearsal size and at production size. A model that looks cheap at forty transactions can dominate the cost at four thousand.
What to record while it runs
Record at the time. Reconstruction afterwards is unreliable, not because people lie but because memory reorganises events into the shape of the outcome. Six fields per transaction attempt are enough, and the fourth one is the one that makes the whole exercise worth doing.
- Signature. For every attempt, including ones you believe failed. A missing signature is itself a data point about the tool's reporting.
- Slot and UTC timestamp. Slot for on-chain ordering, wall clock for correlating with logs from other systems.
- Expected result. Written before the send, in the same terms the criterion uses.
- Observed result. Taken from the chain rather than from the tool's summary, at least for a sample of transactions.
- Verdict. Match, mismatch, or blocked. Not a comment.
- Note. One line, only when something happened that the other five fields cannot carry.
Reading a sample of results from the chain rather than from the tool is a small habit with a large payoff. It is the only check that can detect a reporting defect, where the tool's own account of the run diverges from what actually happened. A tool whose summary always agrees with the chain has earned some trust; you cannot know that without looking.
Abort conditions
Abort conditions are written before the run so that stopping is a lookup rather than a judgement made under stress. Each one needs a number and a scope. "If it looks wrong" is not an abort condition, because during a run everything looks slightly wrong and the person watching will not want to be the one who panicked.
- Cumulative loss threshold. A stated amount, checked after every transaction, at which the run ends regardless of what it is doing.
- Failure rate threshold. A proportion of attempts failing over a stated count, at which the run stops so the failures can be read rather than accumulated.
- Unexpected destination. Any value moving to an address outside the configured set ends the run immediately. This one has no threshold; a single occurrence is enough.
- Authority or approval change. Any instruction that changes an account or mint authority, or grants a token approval you did not configure, ends the run immediately and is irreversible once confirmed.
- Evidence gap. If the record stops being written, the run stops. A rehearsal that continues without evidence is producing risk instead of information.
- Cost divergence. Actual cost per transaction exceeding the prediction by a stated multiple, which usually means a fee or configuration defect rather than a market condition.
Two conditions that are not thresholds
Unexpected destinations and authority changes are not graded. Confirmed Solana transactions cannot be reversed, and an authority change or a token approval can hand control of assets to another party permanently. Treat a single occurrence as an immediate stop, then investigate with the run halted rather than while it continues.
Duration, and why hours are the wrong unit
Rehearsals are usually specified in hours and usually should not be. What you need is exposure to conditions, and conditions do not arrive on a schedule. A run of six quiet hours has tested quiet conditions thoroughly and congested conditions not at all, and the report should say so plainly rather than reporting six hours as though duration were the achievement.
The better specification is event-based with a time cap. The run ends when it has observed the events you care about, or when the cap is reached, whichever comes first, and the report states which of the two ended it. That distinction is the difference between "we tested behaviour under load" and "we hoped for load and did not get it".
Where the automation is multi-venue volume automation that routes across several markets, the events worth waiting for include a route change and a venue becoming unavailable, both of which exercise code paths that a single-venue quiet run never touches. Write those events into the stop condition rather than assuming a long enough run will produce them.
Reading the result
Start with the reconciliation, not with the outcome. Take the wallet's transaction history for the run window and match every entry against the record you kept. Entries the record does not explain are the first finding, and they outrank anything about performance, because they mean the tool did something you did not observe.
Then compare predicted cost against actual. A large divergence in either direction is informative: costing much more than predicted usually means a fee configuration defect or worse price impact than assumed, and costing much less often means fewer transactions landed than you think, which is a different problem wearing a pleasant disguise.
Only then read the criteria verdicts. Most first rehearsals produce a mixture of passes, one or two failures and several inconclusive results because the window was too small. That is a normal and useful outcome. A first rehearsal that produces nothing but passes usually means the criteria were written to be passed.
Scaling up after a pass
Scale in steps you can still abort. Doubling is a reasonable increment because it keeps the arithmetic simple and it keeps each step within reach of the previous evidence; multiplying by ten moves you into behaviour nobody has observed, in the one dimension where the cost curve bends.
At each step, re-check the three things that change with size rather than with code: price impact against available depth, the fee bill in absolute terms, and whether the rate of transactions has started to attract rate limiting from your endpoint. None of those are strategy questions, and all three can invalidate a result that held at half the size.
Finally, write the ceiling into the sign-off. The rehearsal covered a stated size over a stated window, and the report should end with the sentence naming both. Anyone reading it later, including you, needs to know the boundary of what was actually observed, because the temptation to treat a tested small run as a tested system is strong and it is the failure mode this whole layer exists to prevent.
Questions the desk gets asked
What is a dry run in trading bot testing?
It is a live rehearsal on the real network at a deliberately small size, run to observe execution rather than to make money. Everything is real: the funds, the fees, the liquidity and the competition. The only thing scaled down is the amount at risk, and the point is to learn how the system behaves before the amount stops being small.
How is a dry run different from paper trading?
Paper trading simulates the decision and skips execution entirely, so it cannot surface an expired blockhash, a rate-limited endpoint, a failed account creation or a compute limit set too low. A dry run exercises the whole path including the parts that touch the network, which is where most defects in trading automation actually live.
How much money should a dry run risk?
An amount you have already decided to treat as spent before the run starts. The useful framing is not a percentage of capital but a number you would not argue about losing, because the run is a purchase of information and the information is worth the price only if losing it does not change your behaviour mid-run.
When should a dry run be stopped early?
When a written abort condition fires, and only then. Abort conditions are written before the run precisely so that stopping is a lookup rather than a judgement made while watching a loss. Stopping for a reason nobody wrote down is a finding about the plan, and it belongs in the report.
Does a successful dry run mean the bot is safe?
No. It means that at that size, on that day, under the conditions that happened to occur, observed results matched the expectations you wrote. Behaviour at larger size, longer duration or different conditions is untested, and the honest sign-off says which size and which window were covered.
Should a dry run use the production configuration?
Yes, apart from size and risk limits, and every deviation from production has to be listed. A rehearsal run with debug settings, a different endpoint or a different venue is a rehearsal of something else, and the differences are exactly where the untested surface hides.
How many dry runs are enough before scaling?
At least two that agree, because a single clean result is compatible with a favourable accident. After that, the question is not how many runs but which conditions have been observed, and a third run on a quiet afternoon adds much less than a first run during congestion.
Filed under Before you trust it by The QA Ground Desk. Behaviour described here comes from protocol documentation and from procedures the desk can run itself; any figure in an example is labelled as illustrative arithmetic and describes no real account. How the desk decides what to publish is set out in the method note.