Stake Pool Program
A program for pooling together SOL to be staked by an off-chain agent running a Delegation bot which redistributes the stakes across the network and tries to maximize censorship resistance and rewards.
Overview
SOL token holders can earn rewards and help secure the network by staking tokens to one or more validators. Rewards for staked tokens are based on the current inflation rate, total number of SOL staked on the network, and an individual validator’s uptime and commission (fee).
Stake pools are an alternative method of earning staking rewards. This on-chain program pools together SOL to be staked by a staker, allowing SOL holders to stake and earn rewards without managing stakes.
Additional information regarding staking and stake programming is available at:
Motivation
This document is intended for the main actors of the stake pool system:
- manager: creates and manages the stake pool, earns fees, can update the fee, staker, and manager
- staker: adds and removes validators to the pool, rebalances stake among valiators
- user: provides staked SOL into an existing stake pool
In its current iteration, the stake pool only processes totally active stakes. Deposits must come from fully active stakes, and withdrawals return a fully active stake account.
This means that stake pool managers, stakers, and users must be comfortable with creating and delegating stakes, which are more advanced operations than sending and receiving SPL tokens and SOL. Additional information on stake operations are available at:
To reach a wider audience of users, stake pool managers are encouraged to provide a market for their pool's staking derivatives, through an AMM like Token Swap.
Operation
A stake pool manager creates a stake pool, and the staker includes validators that will receive delegations from the pool by creating "validator stake accounts" and activating a delegation on them. Once a validator stake account's delegation is active, the staker adds it to the stake pool.
At this point, users can participate with deposits. They must delegate a stake account to the one of the validators in the stake pool. Once it's active, the user can deposit their stake into the pool in exchange for SPL staking derivatives representing their fractional ownership in pool. A percentage of the rewards earned by the pool goes to the pool manager as a fee.
Over time, as the stake pool accrues staking rewards, the user's fractional ownership will be worth more than their initial deposit. Whenever the user chooses, they can withdraw their SPL staking derivatives in exchange for an activated stake.
The stake pool staker can add and remove validators, or rebalance the pool by withdrawing stakes from the pool, deactivating them, reactivating them on another validator, then depositing back into the pool.
These manager operations require SPL staking derivatives and staked SOL, so the stake pool staker will need liquidity on hand to properly manage the pool.
Background
Solana's programming model and the definitions of the Solana terms used in this document are available at:
Source
The Stake Pool Program's source is available on github.
Command-line Utility
The following explains the instructions available in the Stake Pool Program along with examples using the command-line utility.
The spl-stake-pool
command-line utility can be used to experiment with SPL
tokens. Once you have Rust installed, run:
Run spl-stake-pool --help
for a full description of available commands.
Configuration
The spl-stake-pool
configuration is shared with the solana
command-line tool.
Current Configuration
Cluster RPC URL
See Solana clusters for cluster-specific RPC URLs
Default Keypair
See Keypair conventions for information on how to setup a keypair if you don't already have one.
Keypair File
Hardware Wallet URL (See URL spec)
Stake Pool Manager Examples
Create a stake pool
The stake pool manager controls the stake pool from a high level, and in exchange receives a fee in the form of SPL token staking derivatives. The manager sets the fee on creation. Let's create a pool with a 3% fee:
The unique stake pool identifier is 3CLwo9CntMi4D1enHEFBe3pRJQzGJBCAYe66xFuEbmhC
.
The identifier for the SPL token for staking derivatives is
Gmk71cM7j2RMorRsQrsyysM4HsByQx5PuDGtDdqGLWCS
. The stake pool has full control
over the mint.
The pool creator's fee account identifier is
3xvXPfQi2SaTkqPV9A7BQwh4GyTe2ZPasfoaCBCnTAJ5
. Every epoch, as stake accounts
in the stake pool earn rewards, the program will mint SPL token staking derivatives
equal to 3% of the gains on that epoch into this account.
Set manager
The stake pool manager may pass their administrator privileges to another account.
Set fee
The stake pool manager may update the fee assessed every epoch.
Set staker
In order to manage the stake accounts, the stake pool manager or staker can set the staker authority of the stake pool's managed accounts.
Now, the new staker can perform any normal stake pool operations, including adding and removing validators and rebalancing stake.
Important security note: the stake pool program only gives staking authority to the pool staker and always retains withdraw authority. Therefore, a malicious stake pool staker cannot steal funds from the stake pool.
Note: to avoid "disturbing the manager", the staker can also reassign their stake authority.
Stake Pool Staker Examples
Create a validator stake account
In order to accommodate large numbers of user deposits into the stake pool, the stake pool only manages one stake account per validator. To add a new validator to the stake pool, we first create a validator-associated stake account.
Looking at validators.app or other Solana validator
lists, we choose some validators at random and start with identity
8SQEcP4FaYQySktNQeyxF3w8pvArx3oMEh7fPrzkN9pu
on vote account
2HUKQz7W2nXZSwrdX5RkfS2rLU4j1QZLjdGCHcoUKFh3
. Let's create a validator stake account
delegated to that vote account.
In order to maximize censorship resistance, we want to distribute our SOL to as many validators as possible, so let's add a few more.
NOTE: These stake accounts have not been added to the stake pool yet. Stake pools only accept deposits from fully delegated (warmed-up) stake accounts, so we must first delegate these stakes.
We can see the status of stake account using the Solana command-line utility.
The stake pool creates these special staking accounts with 1 SOL as a minimum
delegation. The stake and withdraw authorities are the keypair configured
with the --config
flag, using the Solana CLI default key. More information
about the Solana CLI can be found on the
Solana Docs.
We must delegate these stake accounts to the vote account specified on creation.
Now that we have delegated the stakes, we need to wait an epoch for the delegation to activate.
Add validator stake account
As mentioned in the last step, the stake pool only manages one stake account per validator. Also, the stake pool only processes fully activated stake accounts. We created new validator stake accounts in the last step and staked them. Once the stake activates, we can add them to the stake pool.
Users can start depositing their activated stakes into the stake pool, as
long as they are delegated to the same vote account, which was
FhFft7ArhZZkh6q4ir1JZMYFgXdH6wkT5M5nmDDb1Q13
in this example. You can also
double-check that at any time using the Solana command-line utility.
Remove validator stake account
If the stake pool staker wants to stop delegating to a vote account, they can
totally remove the validator stake account from the stake pool by providing
staking derivatives, just like withdraw
.
The difference with withdraw
is that the validator stake account is totally
removed from the stake pool and now belongs to the administrator.
We can check the removed stake account:
The administrator's SPL token account has been debited to accommodate the removal of staked SOL from the pool.
We can also double-check that the stake pool no longer shows the stake account:
Rebalance the stake pool
As time goes on, deposits and withdrawals will happen to all of the stake accounts managed by the pool, and the stake pool staker may want to rebalance the stakes.
For example, let's say the staker wants the same delegation to every validator in the pool. When they look at the state of the pool, they see:
This isn't great! The last stake account, E5KBATUd21Dnjnh5sGFw5ngp9kdVXCcAAYMRe2WsVXie
has too much allocated. For their strategy, the staker wants the 15.849959206
SOL to be distributed evenly, meaning around 5.283319735
in each account. They need
to move 4.281036854
to FhFft7ArhZZkh6q4ir1JZMYFgXdH6wkT5M5nmDDb1Q13
and
1.872447062
to FYQB64aEzSmECvnG8RVvdAXBxRnzrLvcA3R22aGH2hUN
.
First, they need to withdraw a total of 6.153483916
from
E5KBATUd21Dnjnh5sGFw5ngp9kdVXCcAAYMRe2WsVXie
. Using the spl-token
utility,
let's check the total supply of pool tokens:
Given a total pool token supply of 0.034692168
and total staked SOL amount of
15.849959206
, let's calculate how many pool tokens to withdraw from the pool:
They withdraw that amount of pool tokens:
Because of rounding in the calculation a few lines above, it looks like we receive less than we should. If we play that back the other way, we'll see that all is well:
Next, they deactivate the new received stake:
Once the stake is deactivated during the next epoch, they split the stake and activate it on the other two validator vote accounts. For brevity, those commands are omitted.
Eventually, we are left with stake account 4zppED2kFodUS2hBf8Fzeepu6yZ6QuyeNPBXCT9VU6fK
with 4.281036854
delegated to 8r1f8mwrUiYdg2Rx9sxTh4M3UAUcCBBrmRA3nxk3Z6Lm
and stake account GCJnuFGCDzaToPwJtG5GiK4g3DJBfuhQy6388NyGcfwf
with 1.872447062
delegated to 2HUKQz7W2nXZSwrdX5RkfS2rLU4j1QZLjdGCHcoUKFh3
.
Once the new stakes are ready, the staker deposits them back into the stake pool:
Leaving them with a rebalanced stake pool!
Due to staking rewards that accrued during the rebalancing process, the pool is not prefectly balanced. This is completely normal.
User Examples
List validator stake accounts
In order to deposit into the stake pool, a user must first delegate some stake to one of the validator stake accounts associated with the stake pool. The command-line utility has a special instruction for finding out which vote accounts are already associated with the stake pool.
If the manager has recently created the stake pool, and there are no stake accounts present yet, the command-line utility will inform us.
Deposit stake
Stake pools only accept deposits from fully staked accounts, so we must first
create stake accounts and delegate them to one of the validators managed by the
stake pool. Using the list
command from the previous section, we see that
2HUKQz7W2nXZSwrdX5RkfS2rLU4j1QZLjdGCHcoUKFh3
is a valid vote account, so let's
create a stake account and delegate our stake there.
Two epochs later, when the stake is fully active and has received one epoch of rewards, we can deposit the stake into the stake pool.
Alternatively, you can create an SPL token account yourself and pass it as the
token-receiver
for the command.
In return, the stake pool has sent us staking derivatives in the form of SPL tokens. We can double-check our stake pool account using the SPL token command-line utility.
Update
Every epoch, the network pays out rewards to stake accounts managed by the stake pool, increasing the value of staking derivative SPL tokens minted on deposit. In order to calculate the proper value of these stake pool tokens, we must update the total value managed by the stake pool every epoch.
If another user already updated the stake pool balance for the current epoch, we see a different output.
If no one updates the stake pool in the current epoch, the deposit and withdraw instructions will fail. The update instruction is permissionless, so any user can run it before depositing or withdrawing.
Withdraw stake
Whenever the user wants to recover SOL plus accrued rewards, they can provide their staking derivative SPL tokens in exchange for an activated stake account.
Let's withdraw 0.02 staking derivative tokens from the stake pool.
The stake pool took 0.02 pool tokens, and in exchange the user received a fully
active stake account, delegated to 2HUKQz7W2nXZSwrdX5RkfS2rLU4j1QZLjdGCHcoUKFh3
.
Let's double-check the status of the stake account:
Alternatively, the user can specify an existing stake account to receive their
stake using the stake-receiver
parameter.
Appendix
Activated stakes
As mentioned earlier, the stake pool only processes active stakes. This feature maintains fungibility of stake pool tokens. Fully activated stakes are not equivalent to inactive, activating, or deactivating stakes due to the time cost of staking. Otherwise, malicious actors can deposit stake in one state and withdraw it in another state without waiting.
Staking Credits Observed on Deposit
A deposited stake account's "credits observed" must match the destination account's "credits observed". Typically, this means you must wait an additional epoch after activation for your stake account to match up with the stake pool's account.
Transaction sizes
The Solana transaction processor has two important limitations:
- size of the overall transaction, limited to roughly 1 MTU / packet
- computation budget per instruction
A stake pool may manage hundreds of staking accounts, so it is impossible to update the total value of the stake pool in one instruction. Thankfully, the command-line utility breaks up transactions to avoid this issue for large pools.