Skip to main content
Use the yield client to stake SOL from an existing Swig wallet. Native Solana staking uses validators on the Swig allowlist. Every call runs on your server for one wallet config. Preparation returns an unsigned PreparedTransaction. If prepareRole reuses an existing role, it returns role metadata instead. Authorize each prepared transaction with the wallet authority. Sign it with your fee payer. Then submit it directly or use sponsored submission, as you would for a transfer. TypeScript exposes swig.yield. Python exposes swig.yields, because yield is a Python keyword. Start with an initialized server client. The Python examples use swig configured with network="mainnet". You can instead pass network on each call. Use your wallet’s network.

How native staking works

  • Deposit. The wallet funds the position’s principal. Your fee payer funds the position’s rent and transaction fees.
  • Rewards. Native rewards compound in the position. They become spendable wallet SOL when you exit and withdraw.
  • Exit. A full exit deactivates the position. A partial exit splits part of a fully active position into a new account, then deactivates that account. Cooldown depends on native staking epochs. Wait until the position is inactive before you withdraw.
  • Withdraw. Returns an inactive position’s balance above its rent reserve to the Swig wallet. The rent reserve stays in the position until the Swig program supports stake account closure through SignV2.
Swig does not set the rates. Rates can change. Normal validator commission and network fees apply.

Choose a validator

listOptions returns the validators on the network’s allowlist and their live rates. Choose a validator with acceptsDeposits set to true for a new deposit. Validators disabled for deposits stay listed. Existing positions can still exit and withdraw while their validator remains on the allowlist.
TypeScript
rate.lastUpdatedAt records the time of the rate observation. The rate can be absent if the current network data cannot produce an annual percentage rate (APR).

Prepare a role that can stake

The signing authority needs a role. All and AllButManageAuthority permit yield operations. A narrower role needs: StakeAll alone cannot authorize Stake program instructions. The role also needs Program(Stake) or ProgramAll. On the current Swig program, ProgramCurated does not cover the Stake program. prepareRole checks the deposit, exit, and withdrawal permissions. It reuses the qualifying role with the lowest role ID held by yieldAuthority. Roles with All or AllButManageAuthority qualify. Other roles need all of:
  • The program permissions in the table above.
  • A general SolLimit or SolRecurringLimit that covers maxDeposit, with no SOL destination restrictions.
  • StakeAll.
Finite stake limits can authorize individual operations. They do not qualify for reuse because withdrawals can include accrued rewards. maxDeposit must be positive. The validator must currently accept deposits. If no role qualifies, prepareRole prepares an AddRole transaction. The new role gets exactly Program(System), Program(Stake), SolLimit(maxDeposit), and StakeAll. It never gets All or ManageAuthority. Existing roles stay unchanged. To create a role, use an Ed25519 or Secp256r1 role-manager authority. That authority must hold an existing role with All or ManageAuthority.
TypeScript
Each operation checks the role’s current permissions again. If a deposit exceeds the remaining SOL allowance, the API returns PERMISSION_DENIED before it builds a transaction. Exits and withdrawals do not spend that SOL allowance.

Deposit

TypeScript
The API derives the position address from your fee payer and positionSeed. Use an ASCII seed of 1–32 bytes. Keep the same seed when you retry. If the address already exists, the API returns ALREADY_EXISTS. Check the earlier submission before you try again. The deposit amount must meet the network’s minimum delegation. The wallet must keep its rent reserve after it funds the deposit.

Exit

TypeScript
A partial exit needs a fully active position. The exiting stake and the remaining stake must each meet the network’s minimum delegation. Your fee payer funds the new position’s rent, returned as additionalRentLamports. Use an ASCII positionSeed of 1–32 bytes. Keep the same seed when you retry. If the split address already exists, the API returns ALREADY_EXISTS.

Withdraw

After cooldown the position is inactive. Withdraw returns its balance above the rent reserve to the Swig wallet.
TypeScript

Read positions, rewards, and estimates

TypeScript
  • Positions include the total balance, rent, positionLamports excluding rent, stake that earns rewards, and indexed withdrawableLamports. Each position has a state: activating, active, deactivating, or inactive.
  • Summary totals positions excluding rent, indexed withdrawableLamports, and recorded rewards. Position balances already include rewards.
  • Rewards are credited native rewards, ordered oldest first by on-chain credit time.
  • Estimates are principal × net APR × days / 365, rounded down, with no compounding, rent, or fees. Days count once the position is fully active.
For an inactive position, indexed withdrawableLamports is the full balance, including rent. In other states, it is only SOL above the delegation and rent reserve. The withdrawal route needs an inactive position and keeps its rent reserve. Use the prepared withdrawal’s withdrawalLamports for the amount the route will return. Positions and rewards come from the Swig index. Each page has 50 entries by default, up to a maximum of 200. A page token works only for its original organization, network, and wallet. lastUpdatedAt is absent until the index first records a position for the wallet.

Errors

See the Yield API reference for the underlying routes.