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.