Stop-loss / infra

Why Trojan's stop loss isn't a stop loss

Trojan's stop loss is a backend watcher, not an on-chain order. Here's why it can slip well past your trigger on volatile small-caps, and what a real stop loss on Solana looks like.

by opal4 min read

Where this stands today: Opal alerts you the instant your stop or target trips. Hands-off execution is in development, behind a spending limit you control — this post explains the design we're building toward.

Trojan has a stop loss. So does BullX. So does every serious Solana trading tool that's shipped in the last two years. None of them stop losses. They stop watching. There's a difference.

I spent several weeks designing Opal's risk module and I hit this the hard way. Here's what I found.

What a client-side stop actually is

When you set a stop on Trojan, you're not putting an order on a book. There is no book. Solana is not an exchange. What Trojan does is monitor your position's price off-chain through their backend. (Their public docs describe AutoSell as "limit sell orders that execute when the trigger is reached" but don't disclose the trigger detection mechanism — and Solana has no native limit-order primitive, so the detection happens off-chain regardless of whose backend runs it.) When the price crosses your threshold, the backend sends a sell transaction to the network. That's the stop.

The problem is what happens between "price crossed threshold" and "sell settled." On Solana, that gap is where your money goes.

The gap has four ways to kill you

The watcher reads a price, decides to sell, submits a transaction, and hopes. Four failure modes sit between those steps. Any one of them breaks the stop:

  • The RPC drops a slot. Solana produces a block every 400ms. The watcher reads prices through an RPC endpoint. If the RPC misses a slot, or returns stale data, the watcher acts on a price from 800ms ago. This happens regularly on public RPCs during volatility spikes. A token can move double-digit percent in that window.
  • Priority fees eat your exit. When volatility spikes, every bot in the pool is trying to exit at once. Priority fees go up. If your stop sell is submitted at the median priority fee, it's at the back of the line. Three slots later your sell lands at a price well below where you triggered.
  • MEV bundles frontrun you. There is a visible mempool on Solana in a meaningful sense. Jito bundles let searchers see your pending sell and route their own sell ahead of yours. You paid the priority fee to not be first.
  • The watcher was down. Not much to add to that one.

Each of these, by itself, is rare. Together, on a volatile small-cap, they stack. The pattern is the one most active traders have seen at least once: a 10% stop fires, the watcher submits, and by the time the sell lands the slot has closed well past the threshold. The stop fired. The position closed. The fill was worse than the worst case the stop was supposed to prevent.

Why "better client-side watcher" is not the fix

The first thing everyone tries is upgrading the RPC. Use Helius. Use a private Jito endpoint. Pay for a dedicated node. These help. They don't solve the problem, because the problem isn't latency. It's the architecture.

The watcher lives off-chain. It reads a price from its RPC, decides to sell, submits a transaction, and hopes. Between those four steps, the four failure modes have four chances to fire. Any one of them breaks the stop.

The fix is to move the stop on-chain. Don't poll for the condition and react. Commit the condition into the transaction and let the chain enforce it.

What a real stop loss on Solana looks like

A real stop loss has one property the polling watcher cannot give you. Execution lives on-chain, enforced by the chain. Not in a backend watcher that might be slow, stale, or off.

That's the design Opal is building toward: a spending limit you control plus on-chain assertion bundles via Lighthouse:

  • You set a limit, not hand over keys. You set a spending limit on each rule — capped, revocable, time-bounded. Opal can trade within it and can do nothing else. Opal never has your seed.
  • Every exit carries its own assertion. The sell transaction includes an on-chain assertion. "Revert this tx unless oracle price is at or below the stop trigger." The sell only lands if the condition still holds.
  • The chain enforces, not us. It's a conditional order on Solana, enforced by the runtime. Not by a polling loop on our backend.
  • Blast radius is bounded. If the key Opal trades with gets compromised tomorrow, the worst case is loss of up to the spending limit you set — never your whole wallet.

It won't be perfect. Markets move between a trigger firing and a tx landing, and no architecture removes that. The number to beat is the off-chain watcher pattern, which on a volatile small-cap stacks the four failure modes above and can slip well past your trigger on a bad slot. We'll publish measured, not modelled, landing rates when it ships.

What Opal does not do is tell you how much of your wallet to risk, how many positions to run, or when to stop for the day. That's your policy, not ours. The stop you set is the stop we're building to enforce. The portfolio picture is shown to you, not used to halt your trading because our opinion of your exposure differs from yours.

What this fix doesn't solve

Honest about what's still on the table:

  • The watcher still needs to fire. If the agent process is down, no transaction is submitted, and the assertion bundle has nothing to enforce against. We're building a more resilient watcher than a backend keeper, but a watcher nonetheless.
  • The trade can still revert. If priority fees are too tight or the price snaps back between firing and settlement, the assertion does its job and the sell doesn't land. That's better than landing at the wrong price, but it's not the same as guaranteed execution. The journal will record each attempt so you can see what fired, what held, and what reverted.
  • MEV beyond the assertion. A searcher selling ahead of you pushes price further past your trigger, and a price ≤ trigger assertion still passes — we'd land at the front-run price. Mitigation lives in priority-fee tuning and Jito bundle routing, not the assertion itself. That's a separate spec.

The residual is physics: markets move between firing and settlement, and the chain enforces what's on the chain at block time. Anything beyond that is a bug in our infrastructure, not physics.

If you're running a tap-to-snipe tool today, your stop loss is not a stop loss. It's a watcher that sends a sell. It will sometimes fire at a price worse than your threshold. On a 5% position in a blue-chip, that's an annoyance. On a 40% position in a small-cap, it's the trade that ends your week.

The fix is not to get angry at Trojan. Trojan ships what most of its users want: fast entry. The fix is to change where the stop lives. A stop that lives in a polling loop on a backend is the 2021 pattern. A stop that lives in an on-chain assertion bundle, behind a spending limit you control, enforced by Solana itself, is what 2026 looks like.

That is what we're building: a spending limit you set — capped, revocable, time-bounded — an assertion on every exit, and a journal that tells you which trigger fired, which assertion held, and which slipped. Until it ships, Opal alerts you the instant your stop or target trips.

Trojan's stop loss stops watching. A stop the chain itself enforces — that's the stop we're building.

Appendix: frequently asked

Why doesn't Trojan's stop loss always fire at my set price?

Because it's a backend watcher, not an order on a book. The watcher reads price through an RPC and then submits a sell transaction. Between those two steps, any of four failure modes (stale RPC slot, priority-fee backlog, MEV bundles, watcher outage) can fire. On a volatile small-cap, your fill can land well below the trigger.

Is there a real on-chain stop loss on Solana?

Not as a native primitive. Solana has no order book. The closest you can build is a transaction that carries an on-chain assertion (using Lighthouse) that reverts the tx if the pre-condition no longer holds. Combined with a capped, revocable on-chain allowance, this gives you a conditional order enforced by the runtime rather than by a backend watcher.

What is a Lighthouse assertion bundle?

Lighthouse is a Solana program that lets you attach assertions to a transaction. If any assertion fails at block time, the whole transaction reverts. Bundling a sell with an assertion like 'revert unless oracle price is at or below trigger' means the sell only lands if the stop-loss condition still holds.

Does Opal hold my keys?

No. Your keys stay yours, and Opal never has your seed. Automated rules trade only within a spending limit you set — capped, revocable, time-bounded. If the key Opal trades with were ever compromised, the worst case is loss of up to the spending limit you set — never your whole wallet.

How reliable will Opal's stop loss be?

Stop and target alerts fire from live monitoring today. Automated execution is in development — we'll publish measured, not modelled, landing rates when it ships.