For the complete documentation index, see llms.txt. This page is also available as Markdown.

Native SOL scenario

A worked, self-contained guide to acting on native SOL — as opposed to an SPL token like USDC. It covers a plain SOL transfer, and staking/unstaking native SOL through the Jito SPL Stake Pool (native SOL in, native SOL out, minting and burning the jitoSOL liquid-staking token). Each example is shown in both execution modes: steps-only (the intermediary already holds SOL / jitoSOL) and quote-with-steps (bridge SOL in, or bridge the proceeds out, in one signed request).

How native SOL differs from an SPL token

Native SOL is not an SPL token, and several rules change because of it:

  • No token account. SOL lives directly in the account's lamport balance — there is no associated token account (ATA) to derive or create. SOL is moved with an explicit System Transfer instruction (programId 11111111111111111111111111111111, discriminator 02000000, a u64 lamports arg, accounts [from, to]). There is no value/lamports field on a step.

  • No wrapping. The service does not wrap SOL into wrapped-SOL. The Jito stake pool takes native SOL in and out directly, which is why it — not a wrapped-SOL Kamino reserve — backs the native flow here.

  • 9 decimals. 1 SOL = 1000000000 lamports. (jitoSOL, an SPL token, also has 9 decimals.)

  • The network fee is charged in native SOL (lamports), debited from the intermediary — see Fees and the rent reserve.

  • Exempt from the "must touch the destination token" guard. A steps-only SPL destination must include a step referencing the dest mint or its ATA. A native-SOL destination has no mint, so this check does not apply.

  • The liquid-staking token is an SPL token. jitoSOL is a normal SPL token, so the intermediary's jitoSOL ATA is a real ATA the service creates in-message if it's missing (billing its one-time rent only when it was). Only the SOL side needs no account.

Everything else — the request envelope, signing with your origin wallet, and the submit call — is the same as for any destination. For the conceptual overview and the two-mode contrast (steps-only vs quote-with-steps), see Using a Solana destination. The mechanics mirror Kamino stake and Kamino withdraw.

Addresses (Jito SPL Stake Pool, Solana mainnet)

Read off-chain 2026-07. The stake-pool accounts are specific to the Jito pool. The programs and sysvars are network constants.

Account
Address

SPL Stake Pool program

SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy

Stake pool (Jito)

Jito4APyf642JPZPx3hGc6WWJ8zPKtRbRs4P815Awbb

Pool withdraw authority (PDA)

6iQKfEyhr3bZMotVkW6beNZz5CPAkiwvgV2CTje9pVSS

Reserve stake account

BgKUXdS29YcHCFrPm5M8oLHiTzZaMDjsebggjoaQ6KFL

Pool mint (jitoSOL)

J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn

Manager fee account

8yoigZfzZ1nNaadumY9uPVD118225UYHTDpmjpr2nrSa

System program

11111111111111111111111111111111

Stake program

Stake11111111111111111111111111111111111111

Clock sysvar

SysvarC1ock11111111111111111111111111111111

Stake history sysvar

SysvarStakeHistory1111111111111111111111111

SPL Token program

TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

The one address you supply yourself for the stake-pool flows is:

  • <intermediary jitoSOL ATA> — the intermediary's associated token account for the jitoSOL pool mint. Derive it from your resolved Solana intermediary and the pool mint (a PDA of [ intermediary, TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA, J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn ] under ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL). Fetch the resolved intermediary from GET /api/v1/executions/{wallet}/intermediaryresult.solana.

The SPL Stake Pool discriminators are single-byte Borsh enum variant indices:

Instruction
Variant
Discriminator

DepositSol

14

0e

WithdrawSol

16

10

System Transfer

02000000

DepositSol's sol-deposit authority and WithdrawSol's sol-withdraw authority are both None (permissionless) on this pool, so the optional trailing authority account is omitted from both instructions.


Example A — transfer native SOL (steps-only)

Moving SOL out of the intermediary is a single System Transfer. No ATA, no create step — the recipient is a plain wallet address.

That's one create request (plus submit). Because the fee is charged in SOL, keep an amount that leaves the intermediary with the fee plus its rent-exempt minimum — or use the three-request carve (Example B, step 1b) to size it exactly.


Example B — stake native SOL (Jito DepositSol)

DepositSol takes native SOL from the intermediary and mints jitoSOL into the intermediary's jitoSOL ATA. A single instruction — no refresh, no lookup tables.

The step

Mode 1 — steps-only (intermediary already holds SOL)

1a. Single-request path (dry: false)

If the amount leaves the intermediary with enough SOL for the fee (and rent), send one dry: false create with lamports set to a concrete value:

1b. Three-request path (adjust the amount by the fee)

To stake close to your whole balance you must leave SOL for the appended fee (and the rent-exempt minimum). Learn the fee, carve the amount, then execute — three requests:

  1. Estimatedry: true create returns result.details.networkFee (lamports):

  2. Adjust lamports to amount − networkFee (and keep the rent-exempt reserve — see below): 500000000 − 15000 = 499985000.

  3. Execute the same request with the carved lamports and dry: false.

The three requests are dry:true estimate → dry:false execute → submit.

Mode 2 — quote-with-steps (bridge SOL in, then stake)

Bridge SOL in from another chain and stake it in one signed request via the quote-backed create endpoint (requires x-api-key). Set lamports to the {MIN_AMOUNT_OUT} placeholder — the service fills the post-fee bridged amount (after also reserving the rent-exempt minimum for native SOL). This is a bridge-in (execution_mode = quote_with_steps).

EXACT_INPUT vs EXACT_OUTPUT — the step is identical. Only quote.swapType / quote.amount and the deposit differ ({AMOUNT_IN} is out-op only and rejected on a bridge-in):

  • EXACT_INPUTquote.amount is the origin token you send. You deposit exactly that. The service stakes arrived − fees.

  • EXACT_OUTPUTquote.amount is the native SOL you want staked (≈ Y). The service grosses the quote up by the fee, and you deposit result.quote.amountIn (origin-token atomic units) to the returned deposit address.


Example C — unstake to native SOL (Jito WithdrawSol)

WithdrawSol burns jitoSOL from the intermediary's jitoSOL ATA and returns native SOL to the intermediary. Note the account order differs from DepositSol and the intermediary appears twice — once as the burn authority, once as the lamport recipient.

The step

Mode 1 — steps-only

Same shape as Example B, Mode 1: one dry: false create for a concrete poolTokens, or the three-request dry:true → dry:false → submit carve when you need to size against the fee. The redeemed SOL lands in the intermediary.

Mode 2 — quote-with-steps (unstake, then bridge SOL out)

To unstake and bridge the SOL out to another chain, use the quote-backed create endpoint with "outOperation": true. A second producer step — a native System Transfer — sends the withdrawn SOL to the 1Click deposit address (a bare wallet for native SOL, not an ATA):

  • EXACT_INPUT — put any u64 in the producer lamports (e.g. the amount you're withdrawing). The service overwrites it with a deterministic quote.amount − networkFee (known up front — not the withdraw's actual on-chain output). Size the WithdrawSol so the SOL it produces covers quote.amount, or the pre-sign simulation reverts (400). There is no {amount} sentinel on the wire — the only backend placeholders are {INTERMEDIARY}, {MIN_AMOUNT_OUT}, {DEPOSIT_ADDRESS}, and {AMOUNT_IN}.

  • EXACT_OUTPUT — put the {AMOUNT_IN} placeholder in the producer lamports. It substitutes to the origin commitment quote.amountIn + network fee, but the producer's amount is then overwritten to quote.amountIn (the fee is a separate injected transfer). 1Click refunds unused slippage. {AMOUNT_IN} is valid only in this position.

An out-operation signs at creation and has no deposit phase.


Fees and the rent reserve

  • The fee is native SOL. For a native-SOL action the service uses its 2-signer gas model (a backend account that is both fee payer and durable-nonce authority, plus your intermediary). The service pays the on-chain SOL gas, then appends a native-lamport Transfer to its service-fee address that debits the intermediary. So the fee comes out of the intermediary's SOL balance — which is why staking or transferring your whole balance fails, and why the three-request carve exists.

  • Rent-exempt reserve. A system account can't be left in the sub-rent "dust" band. On a bridge-in the service reserves the rent-exempt minimum as well as the fee when it resolves {MIN_AMOUNT_OUT}. For a steps-only action you must leave that reserve yourself — size the amount to balance − networkFee − rentReserve.

  • Do not add compute-budget, nonce, or fee instructions — the service injects those. A dry: true preview omits those injected instructions. Steps-only and out-operation echoes are otherwise your submitted steps verbatim, while a bridge-in echo additionally resolves {MIN_AMOUNT_OUT} to its post-fee value. A real create returns the exact transaction the service signs.

Sign and submit

The create response returns, under result.details, a payload to sign and a signingStandardyour origin wallet's standard. Sign result.details.payload with your origin wallet exactly as for any destination — you never handle the inner Solana message — then submit:

The submit body is { signature, executionId } for an EVM or Tron origin. An ed25519 origin (Solana, NEAR, or Stellar) must also include publicKey. A TON origin includes both publicKey and a tonConnect envelope, so its body is { signature, executionId, publicKey, tonConnect }.

Last updated