Solana’s stake program enforces a 2 to 3 day deactivation period. Hubra’s instant unstake routes around it through Sanctum’s shared LST liquidity layer, so you can exit a position in a single block instead of waiting an epoch. This page covers what’s actually happening on-chain, which Sanctum endpoint each path uses, and how to wire the calls programmatically.Documentation Index
Fetch the complete documentation index at: https://docs.hubra.app/llms.txt
Use this file to discover all available pages before exploring further.
Hubra charges no protocol fee on unstake. Cost is price impact only, dynamic and quoted live by Sanctum, starting from around 0.05% in healthy markets.
What it covers
| Source | Output | Path | Sanctum endpoint |
|---|---|---|---|
| Active native stake account | SOL | One transaction | swap/depositStake |
| raSOL | SOL | One transaction | swap/token (instant) |
| raSOL | SOL via stake account | Two phases (~2 to 3d) | swap/withdrawStake (slow) |
| Native stake account (slice) | SOL | Split + route | StakeProgram.split then swap/depositStake |
| raUSDC | USDC | Vault direct-withdraw | Voltr direct-withdraw (no Sanctum) |
How it works under the hood
Native instant: depositStake
Hubra calls Sanctum’s order endpoint:
tx— the unsigned transaction (server-normalized to standard base64 by Hubra).outAmt— the SOL output in lamports.swapSrcData.data.priceImpactPct— the price impact as a fraction.
- Re-authorizes the stake account so Sanctum’s pool can claim it (
StakeProgram.authorize). - Calls Sanctum’s
depositStakeinstruction. The pool absorbs the active stake and mints SOL to the wallet at the pool’s current rate. - The pool runs deactivation in the background; you have already exited.
depositStake consumes the entire stake account. It does not take an amount; partial exits require splitting first (see below).
Liquid instant: pooled token swap
Same shape, different Sanctum endpoint:depositStake at the same SOL notional.
Liquid slow: withdrawStake
For when you want zero price impact and can wait an epoch:
- Burns your raSOL.
- Creates a fresh native stake account, delegated to Hubra’s validator, funded with the underlying SOL.
- Returns control of the stake account to your wallet.
StakeProgram.deactivate manually (or via POST /api/v1/unstake with kind: "deactivate"), wait for the deactivation epoch, and call POST /api/v1/withdraw to close the account.
No fee, no price impact. Costs the same epoch wait as native staking.
Partial unstake on native: how the split works
depositStake is all-or-nothing. To exit only part of a native stake account, the source account is split first.
StakeProgram.split) that creates a new stake account with the same delegation as the parent and the lamports you specified. The split account is active from the moment it exists; no re-activation epoch is needed.
The split account is what gets routed through depositStake. The remaining stake account keeps earning rewards as if nothing happened.
Costs
| Rent for the new (split) account | ~0.002 SOL |
| Sanctum price impact on the slice | varies |
| Hubra protocol fee | None |
| Network fees | Covered by Hubra |
The order response and sanctum_order
Every Sanctum-routed build response carries the original Sanctum order alongside the unsigned transaction:
sanctum_order (along with sanctumKind) back to POST /api/v1/broadcast when using route: "sanctum". Sanctum’s execute endpoint independently validates the signed transaction’s message bytes against the original order and rejects mismatches — that is how the Sanctum router stays safe against tampering.
If you broadcast via route: "rpc" (plain RPC), the chain itself does not need the order; the transaction is self-contained. You lose Sanctum’s MEV-protected broadcaster, but the on-chain effect is identical.
Sanctum kinds
ThesanctumKind field tells /broadcast which Sanctum execute endpoint to use:
sanctumKind | Used by | Sanctum execute endpoint |
|---|---|---|
token | raSOL → SOL instant unstake; SOL → raSOL stake | swap/token/execute |
depositStake | Native instant unstake | swap/depositStake/execute |
withdrawStake | raSOL slow unstake | swap/withdrawStake/execute |
depositSol | (Reserved; not currently used by Hubra flows) | swap/depositSol/execute |
sanctumKind from the build response to /broadcast verbatim. Mismatching it will return 400 invalid_request.
Quoting before you sign
Always quote first for instant unstake at meaningful size. Pool depth changes minute to minute.stakeAccount and the active stake amount in SOL:
outAmt may differ slightly. Treat the quote as a live estimate, not a contract.
The quote endpoint reuses Sanctum’s order endpoint server-side — the unsigned transaction the order also returns is discarded at the boundary. This is why the quote shape mirrors the build shape.
Full reference: POST /api/v1/quote.
When instant pays vs. waiting
Heuristics, not rules. Quote first either way.| Scenario | Recommendation |
|---|---|
| < 50 SOL, immediate need | Instant. Price impact is typically negligible. |
| 50 to 500 SOL, time-sensitive | Instant. Quote first to confirm price impact is below your tolerance. |
| 500 to 1000 SOL, patient | Slow (deactivate). Standard path, no price impact, no fee. |
| 1000+ SOL, time-sensitive | Split across multiple instant unstakes over several hours, or split native:liquid. Quote each leg. |
| 1000+ SOL, patient | Slow (deactivate). The economics dominate the timeline. |
depositStake. This is the practical reason raSOL is the preferred entry point for users who anticipate possibly needing instant exit.
Fees, in detail
| Path | Hubra fee | Sanctum fee | Network fee | Other |
|---|---|---|---|---|
| Native instant | None | Price impact (dynamic) | Covered by Hubra | — |
| raSOL instant | None | Price impact (dynamic) | Covered by Hubra | — |
| raSOL slow | None | None | Covered by Hubra | Epoch wait (~2 to 3d) |
| Partial native instant | None | Price impact on the slice | Covered by Hubra | ~0.002 SOL rent for the split account (covered) |
| USDC instant | None | None | Covered by Hubra | — |
End-to-end example: raSOL instant unstake
strategy with "sol-native-stake" and add stakeAccount. The rest of the shape is identical.
Common questions
Why is the SOL output less than what I unstaked?
Why is the SOL output less than what I unstaked?
Sanctum’s pool charges price impact for absorbing your stake or your raSOL. Hubra adds nothing on top. Larger unstakes consume more pool liquidity and incur higher impact.
Is there a minimum?
Is there a minimum?
0.01 SOL on the native and liquid paths. For partial native unstake, the remaining stake account must keep enough lamports to cover rent exemption (~0.002 SOL).
How fast is "instant"?
How fast is "instant"?
Single transaction. SOL arrives the moment the transaction confirms (typically a few seconds on Solana mainnet).
Why use slow if instant works?
Why use slow if instant works?
Slow has zero cost. If you can wait 2 to 3 days, there is no reason to pay price impact. Instant exists for the cases where waiting is not an option.
What happens if my Sanctum order expires before I broadcast?
What happens if my Sanctum order expires before I broadcast?
The unsigned transaction’s blockhash expires (~2 minutes), and so does the
hubra_token. Rebuild via /unstake and try again. Sanctum order responses are short-lived for this reason.Can I broadcast a Sanctum-routed tx via plain RPC instead?
Can I broadcast a Sanctum-routed tx via plain RPC instead?
Yes —
route: "rpc" works for any signed transaction. You lose Sanctum’s MEV protection and smarter retries, but the on-chain effect is the same.Can agents trigger instant unstake?
Can agents trigger instant unstake?
Yes.
POST /api/v1/unstake with kind: "instant" returns the unsigned transaction; the agent signs locally and broadcasts.Get started
Unstake in the app
Open the app, navigate to your position, choose instant.
POST /api/v1/unstake
Build an unstake transaction programmatically.