From 75ddd9bb229396427977fb679a0763630e83bce6 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Sat, 6 Nov 2021 13:48:11 +0100 Subject: [PATCH] stake-pool-docs: Rearrange docs, add quickstart guide (#2561) * stake-pool-docs: Rearrange docs, add quickstart guide * Rearrange doc sidebar --- docs/sidebars.js | 37 +- docs/src/stake-pool.md | 1105 +---------------- docs/src/stake-pool/cli.md | 822 ++++++++++++ docs/src/stake-pool/overview.md | 271 ++++ docs/src/stake-pool/quickstart.md | 223 ++++ stake-pool/cli/README.md | 68 +- stake-pool/cli/scripts/add-validators.sh | 25 + stake-pool/cli/scripts/deposit-withdraw.sh | 83 -- stake-pool/cli/scripts/deposit.sh | 73 ++ stake-pool/cli/scripts/rebalance.sh | 27 + stake-pool/cli/scripts/setup-local.sh | 61 - stake-pool/cli/scripts/setup-stake-pool.sh | 45 +- .../cli/scripts/setup-test-validator.sh | 56 + stake-pool/cli/scripts/withdraw.sh | 44 + 14 files changed, 1588 insertions(+), 1352 deletions(-) create mode 100644 docs/src/stake-pool/cli.md create mode 100644 docs/src/stake-pool/overview.md create mode 100644 docs/src/stake-pool/quickstart.md create mode 100755 stake-pool/cli/scripts/add-validators.sh delete mode 100755 stake-pool/cli/scripts/deposit-withdraw.sh create mode 100755 stake-pool/cli/scripts/deposit.sh create mode 100755 stake-pool/cli/scripts/rebalance.sh delete mode 100755 stake-pool/cli/scripts/setup-local.sh create mode 100755 stake-pool/cli/scripts/setup-test-validator.sh create mode 100755 stake-pool/cli/scripts/withdraw.sh diff --git a/docs/sidebars.js b/docs/sidebars.js index 6e8a881ef78..c9388b00504 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -1,17 +1,24 @@ module.exports = { - docs: { - "Other Thing": [], - "Solana Program Library (SPL)": [ - "introduction", - "token", - "token-swap", - "token-lending", - "associated-token-account", - "memo", - "name-service", - "shared-memory", - "stake-pool", - "feature-proposal", - ], - }, + docs: [ + "introduction", + "token", + "token-swap", + "token-lending", + "associated-token-account", + "memo", + "name-service", + "shared-memory", + { + type: 'category', + label: 'Stake Pool', + collapsed: true, + items: [ + "stake-pool", + "stake-pool/quickstart", + "stake-pool/overview", + "stake-pool/cli", + ], + }, + "feature-proposal", + ], }; diff --git a/docs/src/stake-pool.md b/docs/src/stake-pool.md index 6414f670563..529df6a0db3 100644 --- a/docs/src/stake-pool.md +++ b/docs/src/stake-pool.md @@ -1,1109 +1,28 @@ --- -title: Stake Pool Program +title: Stake Pool Introduction --- 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 +| Information | Account Address | +| --- | --- | +| Stake Pool Program | `SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy` | -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). +## Getting Started -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. +To get started with stake pools: -Additional information regarding staking and stake programming is available at: - -- https://solana.com/staking -- https://docs.solana.com/staking/stake-programming - -## Quick Start - -If you're looking to get immediately into creating and running a stake pool, -take a look at the -[reference scripts](https://github.com/solana-labs/solana-program-library/tree/master/stake-pool/cli/scripts). - -These scripts require the Solana CLI tool suite, which can be downloaded by -following the instructions at (https://docs.solana.com/cli/install-solana-cli-tools). -Additionally, you must have a usable keypair, created at the default location -using `solana-keygen new`. - -You'll see the following scripts: - -* `setup-local.sh`: sets up a local test validator with validator vote accounts -* `setup-stake-pool.sh`: creates a new stake pool with hardcoded parameters -* `deposit-withdraw.sh`: performs some deposits and withdrawals - -The -[CLI README](https://github.com/solana-labs/solana-program-library/tree/master/stake-pool/cli) -contains more information about each of these scripts. - -## 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 validators -* user: provides staked SOL into an existing stake pool - -In its current iteration, the stake pool accepts active stakes or SOL, so -deposits may come from either an active stake or SOL wallet. Withdrawals -can return a fully active stake account from one of the stake pool's accounts, -or SOL from the reserve. - -This means that stake pool managers and stakers 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: - -- https://docs.solana.com/cli/delegate-stake -- https://docs.solana.com/cli/manage-stake-accounts - -To reach a wider audience of users, stake pool managers are encouraged -to provide a market for their pool's tokens, through an AMM -like [Token Swap](token-swap.md). - -Alternatively, stake pool managers can partner with wallet and stake account -providers for direct SOL deposits. - -## Operation - -A stake pool manager creates a stake pool, and the staker includes validators that will -receive delegations from the pool by adding "validator stake accounts" to the pool -using the `add-validator` instruction. In this command, the stake pool creates -a new stake account and delegates it to the desired validator. - -At this point, users can participate with deposits. They can directly deposit -SOL into the stake pool using the `deposit-sol` instruction. Within this instruction, -the stake pool will move SOL into the pool's reserve account, to be redistributed -by the staker. - -Alternatively, users can deposit a stake account into the pool. To do this, -they must delegate a stake account to the one of the validators in the stake pool. -If the stake pool has a preferred deposit validator, the user must delegate their -stake to that validator's vote account. - -Once the stake becomes active, which happens at the following epoch boundary -(maximum 2 days), the user can deposit their stake into the pool using the -`deposit-stake` instruction. - -In exchange for their deposit (SOL or stake), the user receives SPL tokens -representing their fractional ownership in pool. A percentage of the rewards -earned by the pool goes to the pool manager as an epoch fee. - -Over time, as the stakes in the pool accrue rewards, the user's fractional -ownership will be worth more than their initial deposit. - -Whenever they wish to exit the pool, the user may use the `withdraw-sol` instruction -to receive SOL from the stake pool's reserve in exchange for stake pool tokens. -Note that this operation will fail if there is not enough SOL in the stake pool's -reserve, which is normal if the stake pool manager stakes all of the SOL in the pool. - -Alternatively, they can use the `withdraw-stake` instruction to withdraw an -activated stake account in exchange for their SPL pool tokens. The user will get -back a SOL stake account immediately. The ability to withdraw stake is always -possible, under all circumstances. - -Note: when withdrawing stake, if the user wants to withdraw the SOL in the stake -account, they must first deactivate the stake account and wait until the next -epoch boundary (maximum 2 days). Once the stake is inactive, they can freely -withdraw the SOL. - -The stake pool staker can add and remove validators, or rebalance the pool by -decreasing the stake on a validator, waiting an epoch to move it into the stake -pool's reserve account, then increasing the stake on another validator. - -The staker operation to add a new validator requires 0.00328288 SOL to create -the stake account on a validator, so the stake pool staker will need liquidity -on hand to fully manage the pool stakes. The SOL used to add a new validator -is recovered when removing the validator. - -### Fees - -The stake pool program provides managers many options for making the pool -financially viable, predominantly through fees. There are five different sources -of fees: - -* Epoch: every epoch (roughly 2 days), the stake accounts in the pool earn - inflation rewards, so the stake pool mints pool tokens into the manager's fee - account as a proportion of the earned rewards. For example, if the pool earns - 10 SOL in rewards, and the fee is set to 2%, the manager will earn pool tokens - worth 0.2 SOL. -* SOL withdraw: sends a proportion of the desired withdrawal amount to the manager - For example, if a user wishes to withdraw 100 pool tokens, and the fee is set - to 3%, 3 pool tokens go to the manager, and the remaining 97 tokens go to the - user in the form of a SOL. -* Stake withdraw: sends a proportion of the desired withdrawal amount to the manager - before creating a new stake for the user. -* SOL deposit: converts the entire SOL deposit into pool tokens, then sends a - proportion of those to the manager, and the rest to the user -* Stake deposit: converts the stake account's delegation plus rent-exemption - to pool tokens, sends a proportion of those to the manager, and the rest to - the user - -For partner applications, there's the option of a referral fee on deposits. -During SOL or stake deposits, the stake pool can redistribute a percentage of -the fees to another address as a referral fee. - -This option is particularly attractive for wallet providers. When a wallet -integrates a stake pool, the wallet developer will have the option to earn -additional tokens anytime a user deposits into the stake pool. Stake pool -managers can use this feature to create strategic partnerships and entice -greater adoption of stake pools! - -### Funding restrictions - -To give the manager more control over funds entering the pool, stake pools allow -deposit and withdrawal restrictions on SOL and stakes through three different -"funding authorities": - -* SOL deposit -* Stake deposit -* SOL withdrawal - -If the field is set, that authority must sign the associated instruction. - -For example, if the manager sets a stake deposit authority, then that address -must sign every stake deposit instruction. - -This can also be useful in a few situations: - -* Control who deposits into the stake pool -* Prohibit a form of deposit. For example, the manager only wishes to have SOL - deposits, so they set a stake deposit authority, making it only possible to - deposit a stake account if that authority signs the transaction. -* Maintenance mode. If the pool needs time to reset fees or otherwise, the - manager can temporarily restrict new deposits by setting deposit authorities. - -Note: in order to keep user funds safe, stake withdrawals are always permitted. - -## Background - -Solana's programming model and the definitions of the Solana terms used in this -document are available at: - -- https://docs.solana.com/apps -- https://docs.solana.com/terminology +- [Install the Solana Tools](https://docs.solana.com/cli/install-solana-cli-tools) +- [Install the Stake Pool CLI](stake-pool/cli.md) +- [Step through the quick start guide](stake-pool/quickstart.md) +- [Learn more about stake pools](stake-pool/overview.md) ## Source The Stake Pool Program's source is available on -[GitHub](https://github.com/solana-labs/solana-program-library). +[GitHub](https://github.com/solana-labs/solana-program-library/stake-pool). For information about the types and instructions, the Stake Pool Rust docs are -available at [docs.rs](https://docs.rs/spl-stake-pool/0.5.0/spl_stake_pool/). - -## Security Audits - -Multiple security firms have audited the stake pool program to ensure total -safety of funds. The audit reports are available for reading, presented in descending -chronological order, and the commit hash that each was reviewed at: - -* Quantstamp - - Initial review commit hash [`99914c9`](https://github.com/solana-labs/solana-program-library/tree/99914c9fc7246b22ef04416586ab1722c89576de) - - Re-review commit hash [`3b48fa0`](https://github.com/solana-labs/solana-program-library/tree/3b48fa09d38d1b66ffb4fef186b606f1bc4fdb31) - - Final report https://solana.com/SolanaQuantstampStakePoolAudit.pdf -* Neodyme - - Review commit hash [`0a85a9a`](https://github.com/solana-labs/solana-program-library/tree/0a85a9a533795b6338ea144e433893c6c0056210) - - Report https://solana.com/SolanaNeodymeStakePoolAudit.pdf -* Kudelski - - Review commit hash [`3dd6767`](https://github.com/solana-labs/solana-program-library/tree/3dd67672974f92d3b648bb50ee74f4747a5f8973) - - Report https://solana.com/SolanaKudelskiStakePoolAudit.pdf - -## 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](https://rustup.rs/), run: -```console -$ cargo install spl-stake-pool-cli -``` - -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 - -```console -solana config get -Config File: ${HOME}/.config/solana/cli/config.yml -RPC URL: https://api.mainnet-beta.solana.com -WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed) -Keypair Path: ${HOME}/.config/solana/id.json -``` - -#### Cluster RPC URL - -See [Solana clusters](https://docs.solana.com/clusters) for cluster-specific RPC URLs -```console -solana config set --url https://api.devnet.solana.com -``` - -#### Default Keypair - -See [Keypair conventions](https://docs.solana.com/cli/conventions#keypair-conventions) -for information on how to setup a keypair if you don't already have one. - -Keypair File -```console -solana config set --keypair ${HOME}/new-keypair.json -``` - -Hardware Wallet URL (See [URL spec](https://docs.solana.com/wallet-guide/hardware-wallets#specify-a-keypair-url)) -```console -solana config set --keypair usb://ledger/ -``` - -#### Run Locally - -If you would like to test a stake pool locally without having to wait for stakes -to activate and deactivate, you can run the stake pool locally using the -`solana-test-validator` tool with shorter epochs, and pulling the current program -from devnet. - -```console -$ solana-test-validator -c SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy -c EmiU8AQkB2sswTxVB6aCmsAJftoowZGGDXuytm6X65R3 --url devnet --slots-per-epoch 32 -$ solana config set --url http://127.0.0.1:8899 -``` - -## 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 tokens. The manager -sets the fee on creation. Let's create a pool with a 3% fee and a maximum of 1000 -validator stake accounts: - -```console -$ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 100 --max-validators 1000 -Creating reserve stake DVwDn4LTRztuai4QeenM6fyzgiwUGpVXVNZ1mgKE1Pyc -Creating mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Creating associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Creating pool fee collection account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ -Signature: qQwqahLuC24wPwVdgVXtd7v5htSSPDAH3JxFNmXCv9aDwjjqygQ64VMg3WdPCiNzc4Bn8vtS3qcnUVHVP5MbKgL -Creating stake pool Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Signature: 5z6uH3EuPcujeWGpAjBtciSUR3TxtMBgWYU4ULagUso4QGzE9JenhYHwYthJ4b3rS57ByUNEXTr2BFyF5PjWC42Y -``` - -The unique stake pool identifier is `Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR`. - -The identifier for the stake pool's SPL token mint is -`BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB`. The stake pool has full control -over the mint. - -The pool creator's fee account identifier is -`DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ`. Every epoch, as stake accounts -in the stake pool earn rewards, the program will mint SPL pool tokens -equal to 3% of the gains on that epoch into this account. If no gains were observed, -nothing will be deposited. - -The reserve stake account identifier is `J5XB7mWpeaUZxZ6ogXT57qSCobczx27vLZYSgfSbZoBB`. -This account holds onto additional stake used when rebalancing between validators. - -For a stake pool with 1000 validators, the cost to create a stake pool is less -than 0.5 SOL. - -The `create-pool` command allows setting all of the accounts and keypairs to -pre-generated values, including: - -* stake pool, through the `--pool-keypair` flag -* validator list, through the `--validator-list-keypair` flag -* pool token mint, through the `--mint-keypair` flag -* pool reserve stake account, through the `--reserve-keypair` flag - -Otherwise, these will all default to newly-generated keypairs. - -You can always check out the available options by running `spl-stake-pool create-pool -h`. - -### Create a restricted stake pool - -If a manager would like to restrict deposits (stake and SOL) to one key in -particular, they can set a deposit authority at creation: - -```console -$ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 100 --max-validators 1000 --deposit-authority authority_keypair.json -Creating reserve stake DVwDn4LTRztuai4QeenM6fyzgiwUGpVXVNZ1mgKE1Pyc -Creating mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Creating associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Creating pool fee collection account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ -Signature: qQwqahLuC24wPwVdgVXtd7v5htSSPDAH3JxFNmXCv9aDwjjqygQ64VMg3WdPCiNzc4Bn8vtS3qcnUVHVP5MbKgL -Creating stake pool Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Deposits will be restricted to 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn only, this can be changed using the set-funding-authority command. -Signature: 5z6uH3EuPcujeWGpAjBtciSUR3TxtMBgWYU4ULagUso4QGzE9JenhYHwYthJ4b3rS57ByUNEXTr2BFyF5PjWC42Y -``` - -As the output says, the `set-funding-authority` can be used to modify or remove -the deposit authority. - -As long as the deposit authority is set, SOL and stake deposits must be signed -by `4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn`, so no one else can participate -in the pool. As mentioned earlier, this feature does not prohibit withdrawals, -so anyone with pool tokens will still be able to withdraw from the pool. - -### Set manager - -The stake pool manager may pass their administrator privileges to another account. - -```console -$ spl-stake-pool set-manager Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --new-manager 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 39N5gkaqXuWm6JPEUWfenKXeG4nSa71p7iHb9zurvdZcsWmbjdmSXwLVYfhAVHWucTY77sJ8SkUNpVpVAhe4eZ53 -``` - -At the same time, they may also change the SPL token account that receives fees -every epoch. The mint for the provided token account must be the SPL token mint, -`BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB` in our example. - -```console -$ spl-stake-pool set-manager Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --new-fee-receiver HoCsh97wRxRXVjtG7dyfsXSwH9VxdDzC7GvAsBE1eqJz -Signature: 4aK8yzYvPBkP4PyuXTcCm529kjEH6tTt4ixc5D5ZyCrHwc4pvxAHj6wcr4cpAE1e3LddE87J1GLD466aiifcXoAY -``` - -### Set fee - -The stake pool manager may update any of the fees associated with the stake pool, -passing the numerator and denominator for the fraction that make up the fee. - -For an epoch fee of 10%, they could run: - -```console -$ spl-stake-pool set-fee Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR epoch 10 100 -Signature: 5yPXfVj5cbKBfZiEVi2UR5bXzVDuc2c3ruBwSjkAqpvxPHigwGHiS1mXQVE4qwok5moMWT5RNYAMvkE9bnfQ1i93 -``` - -In order to protect stake pool depositors from malicious managers, the program -applies the new fee for the following epoch. - -For example, if the fee is 1% at epoch 100, and the manager sets it to 10%, the -manager will still gain 1% for the rewards earned during epoch 100. Starting -with epoch 101, the manager will earn 10%. - -Additionally, to prevent a malicious manager from immediately setting the withdrawal -fee to a very high amount, making it practically impossible for users to withdraw, -the stake pool program currently enforces a limit of 1.5x increase per epoch. - -For example, if the current withdrawal fee is 2.5%, the maximum that can be set -for the next epoch is 3.75%. - -The possible options for the fee type are `epoch`, `sol-withdrawal`, -`stake-withdrawal`, `sol-deposit`, and `stake-deposit`. - -### Set referral fee - -The stake pool manager may update the referral fee on deposits at any time, passing -in a percentage amount. - -To set a stake deposit referral fee of 80%, they may run: - -```console -$ spl-stake-pool set-referral-fee Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR stake 80 -Signature: 4vhaBEDhuKkVwMxy7TpyfHEk3Z5kGZKerD1AgajQBdiMRQLZuNZKVR3KQaqbUYZM7UyfRXgkZNdAeP1NfvmwKdqb -``` - -For 80%, this means that 20% of the stake deposit fee goes to the manager, and -80% goes to the referrer. - -### 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. - -```console -$ spl-stake-pool set-staker Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 39N5gkaqXuWm6JPEUWfenKXeG4nSa71p7iHb9zurvdZcsWmbjdmSXwLVYfhAVHWucTY77sJ8SkUNpVpVAhe4eZ53 -``` - -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. - -### Set Funding Authority - -To restrict who can interact with the pool, the stake pool manager may require -a particular signature on stake deposits, SOL deposits, or SOL withdrawals. This -does not make the pool private, since all information is available on-chain, but -it restricts who can use the pool. - -As an example, let's say a pool wants to restrict all SOL withdrawals. - -```console -$ spl-stake-pool set-funding-authority Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR sol-withdraw AZ1PgxWSxw4ezX8gvpNgGsr39jJHCwtkaXr1mNMwWWeK -Signature: 3gx7ckGNSL7gUUyxh4CU3RH3Lyt88hiCvYQ4QRKtnmrZHvAS93ebP6bf39WYGTeKDMVSJUuwBEmk9VFSaWtXsHVV -``` - -After running this command, `AZ1PgxWSxw4ezX8gvpNgGsr39jJHCwtkaXr1mNMwWWeK` must -sign all SOL withdrawals, otherwise the operation fails. - -After some time, if the manager wishes to enable SOL withdrawals, they can remove -the restriction: - -```console -$ spl-stake-pool set-funding-authority Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR sol-withdraw --unset -Signature: 5kWeBqoxyvANMHCP4ydsZRf8QU4hMotLnKkFbTEdvqEVywo4F3MpZtay7D57FbjJZpdp72fc3vrbxJi9qDLfLCnD -``` - -Now, anyone can withdraw SOL from the stake pool, provided there is enough SOL left -in the reserve. - -The options for funding authorities are `sol-withdraw`, `sol-deposit`, and `stake-deposit`. - -Note: it is impossible to restrict stake withdrawals. This would create an opportunity -for malicious pool managers to effectively lock user funds. - -## Stake Pool Staker Examples - -### Add a validator to the pool - -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, the staker must use the `add-validator` command. - -Let's add some random validators to the stake pool. - -```console -$ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk -Adding stake account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt, delegated to 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk -Signature: 5tdpsx64mVcSHBK8vMbBzFDHnEZB6GUmVpqSXXE5hezMAzPYwZbJCBtAHakDAiuWNcrMongGrmwDaeywhVz4i8pi -``` - -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. - -```console -$ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H -Adding stake account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr, delegated to J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H -Signature: 4xeve6gWuiffqBLAMcqa8s7dCMvBmSVdKbDu5WQhigLiXHdCjSNEwoZRexTZji786qgEjXg3nrUh4HcTt3RauZV5 -$ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Adding stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Signature: 4VJYHpPmWkP99TdgYUTgLYixmhqmqsEkWtg4j7zvGZFjYbnLgryu48aV6ub8bqDyULzKckUhb6tvcmZmMX5AFf5G -``` - -We can see the status of a stake account using the Solana command-line utility. - -```console -$ solana stake-account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr -Balance: 0.00328288 SOL -Rent Exempt Reserve: 0.00228288 SOL -Delegated Stake: 0.001 SOL -Active Stake: 0 SOL -Activating Stake: 0.001 SOL -Stake activates starting from epoch: 5 -Delegated Vote Account Address: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H -Stake Authority: DS3AyFN9dF1ruNBcSeo8XXQR8UyVMhcCPcnjU5GnY18S -Withdraw Authority: DS3AyFN9dF1ruNBcSeo8XXQR8UyVMhcCPcnjU5GnY18S -``` - -The stake pool creates these special staking accounts with 0.001 SOL as the required -minimum delegation amount. The stake and withdraw authorities are the stake pool -withdraw authority, program addresses derived from the stake pool's address. - -We can also see the status of the stake pool. - -```console -$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Epoch Fee: 3/100 of epoch rewards -Withdrawal Fee: none -Stake Deposit Fee: none -SOL Deposit Fee: none -SOL Deposit Referral Fee: none -Stake Deposit Referral Fee: none -Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎0.000000000 -Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎0.000000000 Last Update Epoch: 4 -Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎0.000000000 Last Update Epoch: 4 -Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎0.000000000 Last Update Epoch: 4 -Total Pool Stake: ◎0.000000000 -Total Pool Tokens: 0.00000000 -Current Number of Validators: 3 -Max Number of Validators: 1000 -``` - -To make reading easier, the tool will not show balances that cannot be touched by -the stake pool. The stake account `5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr`, -delegated to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`, actually has a balance -of 0.00328288 SOL, but since this is the minimum required amount, it is -not shown by the CLI. - -### 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. - -As with adding a validator, the validator stake account must have exactly -0.00328288 SOL (0.001 SOL delegated, 0.00228288 SOL for rent exemption) to be removed. - -If that is not the case, the staker must first decrease the stake to that minimum amount. -Let's assume that the validator stake account delegated to -`J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H` has a total delegated amount of -7.5 SOL. To reduce that number, the staker can run: - -```console -$ spl-stake-pool decrease-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H 6.5 -Signature: ZpQGwT85rJ8Y9afdkXhKo3TVv4xgTz741mmZj2vW7mihYseAkFsazWxza2y8eNGY4HDJm15c1cStwyiQzaM3RpH -``` - -Now, let's try to remove validator `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`, with -stake account `5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr`. - -```console -$ spl-stake-pool remove-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H -Removing stake account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr, delegated to J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H -Creating account to receive stake nHEEyey8KkgHuVRAUDzkH5Q4PkA4veSHuTxgG6C8L2G -Signature: 4XprnR768Ch6LUvqUVLTjMCiqdYvtjNfECh4izErqwbsASTGjUBz7NtLZHAiraTqhs7b9PoSAazetdsgXa6J4wVu -``` - -Unlike a normal withdrawal, the validator stake account is totally moved from -the stake pool and into a new account belonging to the administrator. - -Note: since removal is only possible when the validator stake is at the minimum -amount of 0.00328288, the administrator does not get any control of user funds, -and only recovers the amount contributed during `add-validator`. - -The authority for the withdrawn stake account can also be specified using the -`--new-authority` flag: - -```console -$ spl-stake-pool remove-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H --new-authority 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 5rrQ3xhDWyiPkUTAQkNAeq31n6sMf1xsg2x9hVY8Vj1NonwBnhxuTv87nADLkwC8Xzc4CGTNCTX2Vph9esWnXk2d -``` - -We can check the removed stake account: - -```console -$ solana stake-account nHEEyey8KkgHuVRAUDzkH5Q4PkA4veSHuTxgG6C8L2G -Balance: 0.003282880 SOL -Rent Exempt Reserve: 0.00328288 SOL -Delegated Stake: 0.001000000 SOL -Active Stake: 0.001000000 SOL -Delegated Vote Account Address: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H -Stake Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Withdraw Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -``` - -### Rebalance the stake pool - -As time goes on, users will deposit to and withdraw from 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: - -```console -$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Epoch Fee: 3/100 of epoch rewards -Withdrawal Fee: none -Stake Deposit Fee: none -SOL Deposit Fee: none -SOL Deposit Referral Fee: none -Stake Deposit Referral Fee: none -Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎10.006848640 -Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎100.000000000 Last Update Epoch: 4 -Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎10.000000000 Last Update Epoch: 4 -Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎10.000000000 Last Update Epoch: 4 -Total Pool Stake: ◎130.006848640 -Total Pool Tokens: 130.00684864 -Current Number of Validators: 3 -Max Number of Validators: 1000 -``` - -This isn't great! The first stake account, `EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ` -has too much allocated. For their strategy, the staker wants the `100` -SOL to be distributed evenly, meaning `40` in each account. They need -to move `30` to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H` and -`38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk`. - -#### Decrease validator stake - -First, they need to decrease the amount on stake account -`3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx`, delegated to -`EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ`, by a total of `60` SOL. - -They decrease that amount of SOL: - -```sh -$ spl-stake-pool decrease-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ 60 -Signature: ZpQGwT85rJ8Y9afdkXhKo3TVv4xgTz741mmZj2vW7mihYseAkFsazWxza2y8eNGY4HDJm15c1cStwyiQzaM3RpH -``` - -Internally, this instruction splits and deactivates 60 SOL from the -validator stake account `3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx` into a -transient stake account, owned and managed entirely by the stake pool. - -Once the stake is deactivated during the next epoch, the `update` command will -automatically merge the transient stake account into a reserve stake account, -also entirely owned and managed by the stake pool. - -#### Increase validator stake - -Now that the reserve stake account has enough to perform the rebalance, the staker -can increase the stake on the two other validators, -`J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H` and -`38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk`. - -They add 30 SOL to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`: - -```sh -$ spl-stake-pool increase-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H 30 -Signature: 3GJACzjUGLPjcd9RLUW86AfBLWKapZRkxnEMc2yHT6erYtcKBgCapzyrVH6VN8Utxj7e2mtvzcigwLm6ZafXyTMw -``` - -And they add 30 SOL to `38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk`: - -```sh -$ spl-stake-pool increase-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk 30 -Signature: 4zaKYu3MQ3as8reLbuHKaXN8FNaHvpHuiZtsJeARo67UKMo6wUUoWE88Fy8N4EYQYicuwULTNffcUD3a9jY88PoU -``` - -Internally, this instruction also uses transient stake accounts. This time, the -stake pool splits from the reserve stake, into the transient stake account, -then activates it to the appropriate validator. - -One to two epochs later, once the transient stakes activate, the `update` command -automatically merges the transient stakes into the validator stake account, leaving -a fully rebalanced stake pool: - -```console -$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Preferred Deposit Validator: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk -Epoch Fee: 3/100 of epoch rewards -Withdrawal Fee: none -Stake Deposit Fee: none -SOL Deposit Fee: none -SOL Deposit Referral Fee: none -Stake Deposit Referral Fee: none -Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎10.006848640 -Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎40.000000000 Last Update Epoch: 8 -Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎40.000000000 Last Update Epoch: 8 -Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎40.000000000 Last Update Epoch: 8 -Total Pool Stake: ◎130.006848640 -Total Pool Tokens: 130.00684864 -Current Number of Validators: 3 -Max Number of Validators: 1000 -``` - -Due to staking rewards that accrued during the rebalancing process, the pool may -not perfectly balanced. This is completely normal. - -### Set Preferred Deposit / Withdraw Validator - -Since a stake pool accepts deposits to any of its stake accounts, and allows -withdrawals from any of its stake accounts, it could be used by malicious arbitrageurs -looking to maximize returns each epoch. - -For example, if a stake pool has 1000 validators, an arbitrageur could stake to -any one of those validators. At the end of the epoch, they can check which -validator has the best performance, deposit their stake, and immediately withdraw -from the highest performing validator. Once rewards are paid out, they can take -their valuable stake, and deposit it back for more than they had. - -To mitigate this arbitrage, a stake pool staker can set a preferred withdraw -or deposit validator. Any deposits or withdrawals must go to the corresponding -stake account, making this attack impossible without a lot of funds. - -Let's set a preferred deposit validator stake account: - -```console -$ spl-stake-pool set-preferred-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR deposit --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Signature: j6fbTqGJ8ehgKnSPns1adaSeFwg5M3wP1a32qYwZsQjymYoSejFUXLNGwvHSouJcFm4C78HUoC8xd7cvb5iActL -``` - -And then let's set the preferred withdraw validator stake account to the same one: - -```console -$ spl-stake-pool set-preferred-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR withdraw --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Signature: 4MKdYLyFqU6H3311YZDeLtsoeGZMzswBHyBCRjHfkzuN1rB4LXJbPfkgUGLKkdbsxJvPRub7SqB1zNPTqDdwti2w -``` - -At any time, they may also unset the preferred validator: - -```console -$ spl-stake-pool set-preferred-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR withdraw --unset -Signature: 5Qh9FA3EXtJ7nKw7UyxmMWXnTMLRKQqcpvfEsEyBtxSPqzPAXp2vFXnPg1Pw8f37JFdvyzYay65CtA8Z1ewzVkvF -``` - -The preferred validators are marked in the `list` command: - -```console -$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Preferred Deposit Validator: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Preferred Withdraw Validator: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -... -``` - -## 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. - -```console -$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -Preferred Deposit Validator: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk -Epoch Fee: 3/100 of epoch rewards -Withdrawal Fee: none -Stake Deposit Fee: none -SOL Deposit Fee: none -SOL Deposit Referral Fee: none -Stake Deposit Referral Fee: none -Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎10.006848640 -Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎35.000000000 Last Update Epoch: 8 -Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎35.000000000 Last Update Epoch: 8 -Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎35.000000000 Last Update Epoch: 8 -Total Pool Stake: ◎115.006848640 -Total Pool Tokens: 115.00684864 -Current Number of Validators: 3 -Max Number of Validators: 1000 -``` - -### Deposit SOL - -Stake pools accept SOL deposits directly from a normal SOL wallet account, and -in exchange mint the appropriate amount of pool tokens. - -```console -$ spl-stake-pool deposit-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 100 -Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 23CptpZaq33njCpJPAvk8XS53xXwpfqF1sGxChk3VDB5mzz7XPKQqwsreun3iwZ6b51AyHqGBaUyc6tx9fqvF9JK -``` - -In return, the stake pool has minted us new pool tokens, representing our share -of ownership in the pool. We can double-check our stake pool account using the -SPL token command-line utility. - -```console -$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -100.00000000 -``` - -### Withdraw SOL - -Stake pools allow SOL withdrawals directly from the reserve and into a normal -SOL wallet account, and in exchange burns the provided pool tokens. - -```console -$ spl-stake-pool withdraw-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8 2 -Signature: 4bqZKUUrjVspqTGqGqX4zxnHnJB67WbeukKUZRmxJ2yFmr275CtHPjZNzQJD9Pe7Q6mSxnUpcVv9FUdAbGP9RyBc -``` - -The stake pool has burned 2 pool tokens, and in return, sent SOL to -`7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8`. - -You can check that the pool tokens have been burned: - -```console -$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -98.00000000 -``` - -And you can check that the recipient has been credited: - -```console -$ solana balance 7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8 -2 SOL -``` - -### Deposit stake - -Stake pools also accept deposits from active stake 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 -`38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk` is a valid vote account, so let's -create a stake account and delegate our stake there. - -```console -$ solana-keygen new --no-passphrase -o stake-account.json -Generating a new keypair -Wrote new keypair to stake-account.json -============================================================================ -pubkey: 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ -============================================================================ -Save this seed phrase to recover your new keypair: -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -============================================================================ -$ solana create-stake-account stake-account.json 10 -Signature: 5Y9r6MNoqJzVX8TWryAJbdp8i2DvintfxbYWoY6VcLEPgphK2tdydhtJTd3o3dF7QdM2Pg8sBFDZuyNcMag3nPvj -$ solana delegate-stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk -Signature: 2cDjHXSHjuadGQf1NQpPi43A8R19aCifsY16yTcictKPHcSAXN5TvXZ58nDJwkYs12tuZfTh5WVgAMSvptfrKdPP -``` - -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. - -```console -$ spl-stake-pool deposit-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ -Depositing stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ into stake pool account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt -Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Signature: 45x2UtA1b49eBPtRHdkvA3k8JneZzfwjptNN1kKQZaPABYiJ4hSA8qwi7qLNN5b3Fr4Z6vXhJprrTCpkk3f8UqgD -``` - -The CLI will default to using the fee payer's -[Associated Token Account](associated-token-account.md) for stake pool tokens -and the withdraw authority on the deposited stake account. - -Alternatively, you can create an SPL token account yourself and pass it as the -`token-receiver` for the command, and specify the withdraw authority on the -stake account using the `withdraw-authority` flag. - -```console -$ spl-stake-pool deposit-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ --token-receiver 34XMHa3JUPv46ftU4dGHvemZ9oKVjnciRePYMcX3rjEF --withdraw-authority authority.json -Depositing stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ into stake pool account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt -Signature: 4AESGZzqBVfj5xQnMiPWAwzJnAtQDRFK1Ha6jqKKTs46Zm5fw3LqgU1mRAT6CKTywVfFMHZCLm1hcQNScSMwVvjQ -``` - -In return, the stake pool has minted us new pool tokens, representing our share -of ownership in the pool. We can double-check our stake pool account using the -SPL token command-line utility. - -```console -$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB -10.00000000 -``` - -#### Note on stake deposit fee - -Stake pools have separate fees for stake and SOL, so the total fee from depositing -a stake account is calculated from the rent-exempt reserve as SOL, and the delegation -as stake. - -For example, if a stake pool has a stake deposit fee of 1%, and a SOL deposit fee -of 5%, and you deposit a stake account with 10 SOL in stake, and .00228288 SOL -in rent-exemption, the total fee charged is: - -``` -total_fee = stake_delegation * stake_deposit_fee + rent_exemption * sol_deposit_fee -total_fee = 10 * 1% + .00228288 * 5% -total_fee = 0.100114144 -``` - -### Update - -Every epoch, the network pays out rewards to stake accounts managed by the stake -pool, increasing the value of pool 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. - -```console -$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Signature: 2rtPNGKFSSnXFCb6MKG5wHp34dkB5hJWNhro8EU2oGh1USafAgzu98EgoRnPLi7ojQfmTpvXk4S7DWXYGu5t85Ka -Signature: 5V2oCNvZCNJfC6QXHmR2UHGxVMip6nfZixYkVjFQBTyTf2Z9s9GJ9BjkxSFGvUsvW6zc2cCRv9Lqucu1cgHMFcVU -``` - -If another user already updated the stake pool balance for the current epoch, we -see a different output. - -```sh -$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR -Update not required -``` - -If no one updates the stake pool in the current epoch, all instructions, including -deposit and withdraw, will fail. The update instruction is permissionless, so any user -can run it before interacting with the pool. As a convenience, the CLI attempts -to update before running any instruction on the stake pool. - -If the stake pool transient stakes are in an unexpected state, and merges are -not possible, there is the option to only update the stake pool balances without -performing merges using the `--no-merge` flag. - -```sh -$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --no-merge -Signature: 5cjdZG727uzwnEEG3vJ1vskA9WsXibaEHh7imXSb2S1cwEYK4Q3btr2GEeAV8EffK4CEQ2WM6PQxawkJAHoZ4jsQ -Signature: EBHbSRstJ3HxKwYKak8vEwVMKr1UBxdbqs5KuX3XYt4ppPjhaziGEtvL2TJCm1HLokbrtMeTEv57Ef4xhByJtJP -``` - -Later on, whenever the transient stakes are ready to be merged, it is possible to -force another update in the same epoch using the `--force` flag. - -```sh -$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --force -Signature: 5RneEBwJkFytBJaJdkvCTHFrG3QzE3SGf9vdBm9gteCcHV4HwaHzj3mjX1hZg4yCREQSgmo3H9bPF6auMmMFTSTo -Signature: 1215wJUY7vj82TQoGCacQ2VJZ157HnCTvfsUXkYph3nZzJNmeDaGmy1nCD7hkhFfxnQYYxVtec5TkDFGGB4e7EvG -``` - -### Withdraw stake - -Whenever the user wants to recover their SOL plus accrued rewards, they can provide their -pool tokens in exchange for an activated stake account. - -Let's withdraw active staked SOL in exchange for 5 pool tokens. - -```console -$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 -Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Creating account to receive stake 5GuAyPAt6577HoGhSVRNBv6aHohVtjQ8q7q5i3X1p4tB -Signature: 5fzaKt5MU8bLjJRgNZyEktKsgweSQzFRpubCGKPeuk9shNQb4CtTkbgZ2X5MmC1VRDZ3YcCTPdtL9sFpXYfoqaeV -``` - -The stake pool took 5 pool tokens, and in exchange the user received a fully -active stake account, delegated to `EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ`. -Let's double-check the status of the stake account: - -```console -$ solana stake-account 5GuAyPAt6577HoGhSVRNBv6aHohVtjQ8q7q5i3X1p4tB -Balance: 5.00228288 SOL -Rent Exempt Reserve: 0.00228288 SOL -Delegated Stake: 5 SOL -Active Stake: 5 SOL -Delegated Vote Account Address: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Stake Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -Withdraw Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn -``` - -Note: this operation cost the user some funds, as they needed to create a new -stake account with the minimum rent exemption in order to receive the funds. This -allows the user to withdraw any amount of stake pool tokens, even if it is not -enough to cover the stake account rent-exemption. - -Alternatively, the user can specify an existing uninitialized stake account to -receive their stake using the `--stake-receiver` parameter. - -```console -$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --amount 0.02 --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ --stake-receiver CZF2z3JJoDmJRcVjtsrz1BKUUGNL3VPW5FPFqge1bzmQ -Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Signature: 2xBPVPJ749AE4hHNCNYdjuHv1EdMvxm9uvvraWfTA7Urrvecwh9w64URCyLLroLQ2RKDGE2QELM2ZHd8qRkjavJM -``` - -By default, the withdraw command uses the `token-owner`'s associated token account to -source the pool tokens. It's possible to specify the SPL token account using -the `--pool-account` flag. - -```console -$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 --pool-account 34XMHa3JUPv46ftU4dGHvemZ9oKVjnciRePYMcX3rjEF -Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Creating account to receive stake CZF2z3JJoDmJRcVjtsrz1BKUUGNL3VPW5FPFqge1bzmQ -Signature: 2xBPVPJ749AE4hHNCNYdjuHv1EdMvxm9uvvraWfTA7Urrvecwh9w64URCyLLroLQ2RKDGE2QELM2ZHd8qRkjavJM -``` - -By default, the withdraw command will withdraw from the largest validator stake -accounts in the pool. It's also possible to specify a specific vote account for -the withdraw using the `--vote-account` flag. - -```console -$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --amount 5 --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ -Creating account to receive stake CZF2z3JJoDmJRcVjtsrz1BKUUGNL3VPW5FPFqge1bzmQ -Signature: 2xBPVPJ749AE4hHNCNYdjuHv1EdMvxm9uvvraWfTA7Urrvecwh9w64URCyLLroLQ2RKDGE2QELM2ZHd8qRkjavJM -``` - -Note that the associated validator stake account must have enough lamports to -satisfy the pool token amount requested. - -#### Special case: exiting pool with a delinquent staker - -With the reserve stake, it's possible for a delinquent or malicious staker to -move all stake into the reserve through `decrease-validator-stake`, so the -pool tokens will not gain rewards, and the stake pool users will not -be able to withdraw their funds. - -To get around this case, it is also possible to withdraw from the stake pool's -reserve, but only if all of the validator stake accounts are at the minimum amount of -`0.001 SOL + stake account rent exemption`. - -```console -$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 --use-reserve -Withdrawing ◎5.000000000, or 5 pool tokens, from stake account J5XB7mWpeaUZxZ6ogXT57qSCobczx27vLZYSgfSbZoBB -Creating account to receive stake 51XdXiBSsVzeuY79xJwWAGZgeKzzgFKWajkwvWyrRiNE -Signature: yQH9n7Go6iCMEYXqWef38ZYBPwXDmbwKAJFJ4EHD6TusBpusKsfNuT3TV9TL8FmxR2N9ExZTZwbD9Njc3rMvUcf -``` - -## 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. - -### Transient stake accounts - -Each validator gets one transient stake account, so the staker can only -perform one action at a time on a validator. It's impossible to increase -and decrease the stake on a validator at the same time. The staker must wait for -the existing transient stake account to get merged during an `update` instruction -before performing a new action. - -### Reserve stake account - -Every stake pool is initialized with an undelegated reserve stake account, used -to hold undelegated stake in process of rebalancing. After the staker decreases -the stake on a validator, one epoch later, the update operation will merge the -decreased stake into the reserve. Conversely, whenever the staker increases the -stake on a validator, the lamports are drawn from the reserve stake account. - -### Safety of Funds - -One of the primary aims of the stake pool program is to always allow pool token -holders to withdraw their funds at any time. - -To that end, let's look at the three classes of stake accounts in the stake pool system: - -* validator stake: active stake accounts, one per validator in the pool -* transient stake: activating or deactivating stake accounts, merged into the reserve after deactivation, or into the validator stake after activation, one per validator -* reserve stake: inactive stake, to be used by the staker for rebalancing - -Additionally, the staker may set a "preferred withdraw account", which forces users -to withdraw from a particular stake account. This is to prevent malicious -depositors from using the stake pool as a free conversion between validators. - -When processing withdrawals, the order of priority goes: - -* preferred withdraw validator stake account (if set) -* validator stake accounts -* transient stake accounts -* reserve stake account - -If there is preferred withdraw validator, and that validator stake account has -any SOL, a user must withdraw from that account. - -If that account is empty, or the preferred withdraw validator stake account is -not set, then the user must withdraw from any validator stake account. - -If all validator stake accounts are empty, which may happen if the stake pool -staker decreases the stake on all validators at once, then the user must withdraw -from any transient stake account. - -If all transient stake accounts are empty, then the user must withdraw from the -reserve. - -In this way, a user's funds are never at risk, and always redeemable. - -### 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. +available at [docs.rs](https://docs.rs/spl-stake-pool/0.6.3/spl_stake_pool/). diff --git a/docs/src/stake-pool/cli.md b/docs/src/stake-pool/cli.md new file mode 100644 index 00000000000..3ce9f9e4d87 --- /dev/null +++ b/docs/src/stake-pool/cli.md @@ -0,0 +1,822 @@ +--- +title: Command-line Interface +--- + +The following explains the instructions available in the Stake Pool Program along +with examples using the command-line utility. + +## Installation + +The `spl-stake-pool` command-line utility can be used to experiment with SPL +tokens. Once you have [Rust installed](https://rustup.rs/), run: +```console +$ cargo install spl-stake-pool-cli +``` + +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 + +```console +$ solana config get +Config File: ${HOME}/.config/solana/cli/config.yml +RPC URL: https://api.mainnet-beta.solana.com +WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed) +Keypair Path: ${HOME}/.config/solana/id.json +``` + +### Cluster RPC URL + +See [Solana clusters](https://docs.solana.com/clusters) for cluster-specific RPC URLs +```console +$ solana config set --url https://api.devnet.solana.com +``` + +### Default Keypair + +See [Keypair conventions](https://docs.solana.com/cli/conventions#keypair-conventions) +for information on how to setup a keypair if you don't already have one. + +Keypair File +```console +$ solana config set --keypair ${HOME}/new-keypair.json +``` + +Hardware Wallet URL (See [URL spec](https://docs.solana.com/wallet-guide/hardware-wallets#specify-a-keypair-url)) +```console +$ solana config set --keypair usb://ledger/ +``` + +### Running Locally + +If you would like to test a stake pool locally without having to wait for stakes +to activate and deactivate, you can run the stake pool locally using the +`solana-test-validator` tool with shorter epochs, and pulling the current program +from devnet. + +```console +$ solana-test-validator -c SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy -c EmiU8AQkB2sswTxVB6aCmsAJftoowZGGDXuytm6X65R3 --url devnet --slots-per-epoch 32 +$ solana config set --url http://127.0.0.1:8899 +``` + +## 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 tokens. The manager +sets the fee on creation. Let's create a pool with a 3% fee and a maximum of 1000 +validator stake accounts: + +```console +$ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 100 --max-validators 1000 +Creating reserve stake DVwDn4LTRztuai4QeenM6fyzgiwUGpVXVNZ1mgKE1Pyc +Creating mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Creating associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Creating pool fee collection account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ +Signature: qQwqahLuC24wPwVdgVXtd7v5htSSPDAH3JxFNmXCv9aDwjjqygQ64VMg3WdPCiNzc4Bn8vtS3qcnUVHVP5MbKgL +Creating stake pool Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Signature: 5z6uH3EuPcujeWGpAjBtciSUR3TxtMBgWYU4ULagUso4QGzE9JenhYHwYthJ4b3rS57ByUNEXTr2BFyF5PjWC42Y +``` + +The unique stake pool identifier is `Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR`. + +The identifier for the stake pool's SPL token mint is +`BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB`. The stake pool has full control +over the mint. + +The pool creator's fee account identifier is +`DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ`. Every epoch, as stake accounts +in the stake pool earn rewards, the program will mint SPL pool tokens +equal to 3% of the gains on that epoch into this account. If no gains were observed, +nothing will be deposited. + +The reserve stake account identifier is `J5XB7mWpeaUZxZ6ogXT57qSCobczx27vLZYSgfSbZoBB`. +This account holds onto additional stake used when rebalancing between validators. + +For a stake pool with 1000 validators, the cost to create a stake pool is less +than 0.5 SOL. + +The `create-pool` command allows setting all of the accounts and keypairs to +pre-generated values, including: + +* stake pool, through the `--pool-keypair` flag +* validator list, through the `--validator-list-keypair` flag +* pool token mint, through the `--mint-keypair` flag +* pool reserve stake account, through the `--reserve-keypair` flag + +Otherwise, these will all default to newly-generated keypairs. + +You can always check out the available options by running `spl-stake-pool create-pool -h`. + +### Create a restricted stake pool + +If a manager would like to restrict deposits (stake and SOL) to one key in +particular, they can set a deposit authority at creation: + +```console +$ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 100 --max-validators 1000 --deposit-authority authority_keypair.json +Creating reserve stake DVwDn4LTRztuai4QeenM6fyzgiwUGpVXVNZ1mgKE1Pyc +Creating mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Creating associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Creating pool fee collection account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ +Signature: qQwqahLuC24wPwVdgVXtd7v5htSSPDAH3JxFNmXCv9aDwjjqygQ64VMg3WdPCiNzc4Bn8vtS3qcnUVHVP5MbKgL +Creating stake pool Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Deposits will be restricted to 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn only, this can be changed using the set-funding-authority command. +Signature: 5z6uH3EuPcujeWGpAjBtciSUR3TxtMBgWYU4ULagUso4QGzE9JenhYHwYthJ4b3rS57ByUNEXTr2BFyF5PjWC42Y +``` + +As the output says, the `set-funding-authority` can be used to modify or remove +the deposit authority. + +As long as the deposit authority is set, SOL and stake deposits must be signed +by `4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn`, so no one else can participate +in the pool. As mentioned earlier, this feature does not prohibit withdrawals, +so anyone with pool tokens will still be able to withdraw from the pool. + +### Set manager + +The stake pool manager may pass their administrator privileges to another account. + +```console +$ spl-stake-pool set-manager Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --new-manager 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 39N5gkaqXuWm6JPEUWfenKXeG4nSa71p7iHb9zurvdZcsWmbjdmSXwLVYfhAVHWucTY77sJ8SkUNpVpVAhe4eZ53 +``` + +At the same time, they may also change the SPL token account that receives fees +every epoch. The mint for the provided token account must be the SPL token mint, +`BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB` in our example. + +```console +$ spl-stake-pool set-manager Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --new-fee-receiver HoCsh97wRxRXVjtG7dyfsXSwH9VxdDzC7GvAsBE1eqJz +Signature: 4aK8yzYvPBkP4PyuXTcCm529kjEH6tTt4ixc5D5ZyCrHwc4pvxAHj6wcr4cpAE1e3LddE87J1GLD466aiifcXoAY +``` + +### Set fee + +The stake pool manager may update any of the fees associated with the stake pool, +passing the numerator and denominator for the fraction that make up the fee. + +For an epoch fee of 10%, they could run: + +```console +$ spl-stake-pool set-fee Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR epoch 10 100 +Signature: 5yPXfVj5cbKBfZiEVi2UR5bXzVDuc2c3ruBwSjkAqpvxPHigwGHiS1mXQVE4qwok5moMWT5RNYAMvkE9bnfQ1i93 +``` + +In order to protect stake pool depositors from malicious managers, the program +applies the new fee for the following epoch. + +For example, if the fee is 1% at epoch 100, and the manager sets it to 10%, the +manager will still gain 1% for the rewards earned during epoch 100. Starting +with epoch 101, the manager will earn 10%. + +Additionally, to prevent a malicious manager from immediately setting the withdrawal +fee to a very high amount, making it practically impossible for users to withdraw, +the stake pool program currently enforces a limit of 1.5x increase per epoch. + +For example, if the current withdrawal fee is 2.5%, the maximum that can be set +for the next epoch is 3.75%. + +The possible options for the fee type are `epoch`, `sol-withdrawal`, +`stake-withdrawal`, `sol-deposit`, and `stake-deposit`. + +### Set referral fee + +The stake pool manager may update the referral fee on deposits at any time, passing +in a percentage amount. + +To set a stake deposit referral fee of 80%, they may run: + +```console +$ spl-stake-pool set-referral-fee Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR stake 80 +Signature: 4vhaBEDhuKkVwMxy7TpyfHEk3Z5kGZKerD1AgajQBdiMRQLZuNZKVR3KQaqbUYZM7UyfRXgkZNdAeP1NfvmwKdqb +``` + +For 80%, this means that 20% of the stake deposit fee goes to the manager, and +80% goes to the referrer. + +### 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. + +```console +$ spl-stake-pool set-staker Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 39N5gkaqXuWm6JPEUWfenKXeG4nSa71p7iHb9zurvdZcsWmbjdmSXwLVYfhAVHWucTY77sJ8SkUNpVpVAhe4eZ53 +``` + +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. + +### Set Funding Authority + +To restrict who can interact with the pool, the stake pool manager may require +a particular signature on stake deposits, SOL deposits, or SOL withdrawals. This +does not make the pool private, since all information is available on-chain, but +it restricts who can use the pool. + +As an example, let's say a pool wants to restrict all SOL withdrawals. + +```console +$ spl-stake-pool set-funding-authority Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR sol-withdraw AZ1PgxWSxw4ezX8gvpNgGsr39jJHCwtkaXr1mNMwWWeK +Signature: 3gx7ckGNSL7gUUyxh4CU3RH3Lyt88hiCvYQ4QRKtnmrZHvAS93ebP6bf39WYGTeKDMVSJUuwBEmk9VFSaWtXsHVV +``` + +After running this command, `AZ1PgxWSxw4ezX8gvpNgGsr39jJHCwtkaXr1mNMwWWeK` must +sign all SOL withdrawals, otherwise the operation fails. + +After some time, if the manager wishes to enable SOL withdrawals, they can remove +the restriction: + +```console +$ spl-stake-pool set-funding-authority Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR sol-withdraw --unset +Signature: 5kWeBqoxyvANMHCP4ydsZRf8QU4hMotLnKkFbTEdvqEVywo4F3MpZtay7D57FbjJZpdp72fc3vrbxJi9qDLfLCnD +``` + +Now, anyone can withdraw SOL from the stake pool, provided there is enough SOL left +in the reserve. + +The options for funding authorities are `sol-withdraw`, `sol-deposit`, and `stake-deposit`. + +Note: it is impossible to restrict stake withdrawals. This would create an opportunity +for malicious pool managers to effectively lock user funds. + +## Stake Pool Staker Examples + +### Add a validator to the pool + +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, the staker must use the `add-validator` command. + +Let's add some random validators to the stake pool. + +```console +$ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk +Adding stake account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt, delegated to 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk +Signature: 5tdpsx64mVcSHBK8vMbBzFDHnEZB6GUmVpqSXXE5hezMAzPYwZbJCBtAHakDAiuWNcrMongGrmwDaeywhVz4i8pi +``` + +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. + +```console +$ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +Adding stake account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr, delegated to J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +Signature: 4xeve6gWuiffqBLAMcqa8s7dCMvBmSVdKbDu5WQhigLiXHdCjSNEwoZRexTZji786qgEjXg3nrUh4HcTt3RauZV5 +$ spl-stake-pool add-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Adding stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Signature: 4VJYHpPmWkP99TdgYUTgLYixmhqmqsEkWtg4j7zvGZFjYbnLgryu48aV6ub8bqDyULzKckUhb6tvcmZmMX5AFf5G +``` + +We can see the status of a stake account using the Solana command-line utility. + +```console +$ solana stake-account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr +Balance: 0.00328288 SOL +Rent Exempt Reserve: 0.00228288 SOL +Delegated Stake: 0.001 SOL +Active Stake: 0 SOL +Activating Stake: 0.001 SOL +Stake activates starting from epoch: 5 +Delegated Vote Account Address: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +Stake Authority: DS3AyFN9dF1ruNBcSeo8XXQR8UyVMhcCPcnjU5GnY18S +Withdraw Authority: DS3AyFN9dF1ruNBcSeo8XXQR8UyVMhcCPcnjU5GnY18S +``` + +The stake pool creates these special staking accounts with 0.001 SOL as the required +minimum delegation amount. The stake and withdraw authorities are the stake pool +withdraw authority, program addresses derived from the stake pool's address. + +We can also see the status of the stake pool. + +```console +$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Epoch Fee: 3/100 of epoch rewards +Withdrawal Fee: none +Stake Deposit Fee: none +SOL Deposit Fee: none +SOL Deposit Referral Fee: none +Stake Deposit Referral Fee: none +Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎0.000000000 +Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎0.000000000 Last Update Epoch: 4 +Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎0.000000000 Last Update Epoch: 4 +Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎0.000000000 Last Update Epoch: 4 +Total Pool Stake: ◎0.000000000 +Total Pool Tokens: 0.00000000 +Current Number of Validators: 3 +Max Number of Validators: 1000 +``` + +To make reading easier, the tool will not show balances that cannot be touched by +the stake pool. The stake account `5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr`, +delegated to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`, actually has a balance +of 0.00328288 SOL, but since this is the minimum required amount, it is +not shown by the CLI. + +### 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. + +As with adding a validator, the validator stake account must have exactly +0.00328288 SOL (0.001 SOL delegated, 0.00228288 SOL for rent exemption) to be removed. + +If that is not the case, the staker must first decrease the stake to that minimum amount. +Let's assume that the validator stake account delegated to +`J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H` has a total delegated amount of +7.5 SOL. To reduce that number, the staker can run: + +```console +$ spl-stake-pool decrease-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H 6.5 +Signature: ZpQGwT85rJ8Y9afdkXhKo3TVv4xgTz741mmZj2vW7mihYseAkFsazWxza2y8eNGY4HDJm15c1cStwyiQzaM3RpH +``` + +Now, let's try to remove validator `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`, with +stake account `5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr`. + +```console +$ spl-stake-pool remove-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +Removing stake account 5AaobwjccyHnXhFCd24uiX6VqPjXE3Ry4o92fJjqqjAr, delegated to J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +Creating account to receive stake nHEEyey8KkgHuVRAUDzkH5Q4PkA4veSHuTxgG6C8L2G +Signature: 4XprnR768Ch6LUvqUVLTjMCiqdYvtjNfECh4izErqwbsASTGjUBz7NtLZHAiraTqhs7b9PoSAazetdsgXa6J4wVu +``` + +Unlike a normal withdrawal, the validator stake account is totally moved from +the stake pool and into a new account belonging to the administrator. + +Note: since removal is only possible when the validator stake is at the minimum +amount of 0.00328288, the administrator does not get any control of user funds, +and only recovers the amount contributed during `add-validator`. + +The authority for the withdrawn stake account can also be specified using the +`--new-authority` flag: + +```console +$ spl-stake-pool remove-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H --new-authority 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 5rrQ3xhDWyiPkUTAQkNAeq31n6sMf1xsg2x9hVY8Vj1NonwBnhxuTv87nADLkwC8Xzc4CGTNCTX2Vph9esWnXk2d +``` + +We can check the removed stake account: + +```console +$ solana stake-account nHEEyey8KkgHuVRAUDzkH5Q4PkA4veSHuTxgG6C8L2G +Balance: 0.003282880 SOL +Rent Exempt Reserve: 0.00328288 SOL +Delegated Stake: 0.001000000 SOL +Active Stake: 0.001000000 SOL +Delegated Vote Account Address: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +Stake Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Withdraw Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +``` + +### Rebalance the stake pool + +As time goes on, users will deposit to and withdraw from 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: + +```console +$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Epoch Fee: 3/100 of epoch rewards +Withdrawal Fee: none +Stake Deposit Fee: none +SOL Deposit Fee: none +SOL Deposit Referral Fee: none +Stake Deposit Referral Fee: none +Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎10.006848640 +Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎100.000000000 Last Update Epoch: 4 +Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎10.000000000 Last Update Epoch: 4 +Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎10.000000000 Last Update Epoch: 4 +Total Pool Stake: ◎130.006848640 +Total Pool Tokens: 130.00684864 +Current Number of Validators: 3 +Max Number of Validators: 1000 +``` + +This isn't great! The first stake account, `EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ` +has too much allocated. For their strategy, the staker wants the `100` +SOL to be distributed evenly, meaning `40` in each account. They need +to move `30` to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H` and +`38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk`. + +#### Decrease validator stake + +First, they need to decrease the amount on stake account +`3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx`, delegated to +`EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ`, by a total of `60` SOL. + +They decrease that amount of SOL: + +```sh +$ spl-stake-pool decrease-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ 60 +Signature: ZpQGwT85rJ8Y9afdkXhKo3TVv4xgTz741mmZj2vW7mihYseAkFsazWxza2y8eNGY4HDJm15c1cStwyiQzaM3RpH +``` + +Internally, this instruction splits and deactivates 60 SOL from the +validator stake account `3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx` into a +transient stake account, owned and managed entirely by the stake pool. + +Once the stake is deactivated during the next epoch, the `update` command will +automatically merge the transient stake account into a reserve stake account, +also entirely owned and managed by the stake pool. + +#### Increase validator stake + +Now that the reserve stake account has enough to perform the rebalance, the staker +can increase the stake on the two other validators, +`J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H` and +`38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk`. + +They add 30 SOL to `J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H`: + +```sh +$ spl-stake-pool increase-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H 30 +Signature: 3GJACzjUGLPjcd9RLUW86AfBLWKapZRkxnEMc2yHT6erYtcKBgCapzyrVH6VN8Utxj7e2mtvzcigwLm6ZafXyTMw +``` + +And they add 30 SOL to `38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk`: + +```sh +$ spl-stake-pool increase-validator-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk 30 +Signature: 4zaKYu3MQ3as8reLbuHKaXN8FNaHvpHuiZtsJeARo67UKMo6wUUoWE88Fy8N4EYQYicuwULTNffcUD3a9jY88PoU +``` + +Internally, this instruction also uses transient stake accounts. This time, the +stake pool splits from the reserve stake, into the transient stake account, +then activates it to the appropriate validator. + +One to two epochs later, once the transient stakes activate, the `update` command +automatically merges the transient stakes into the validator stake account, leaving +a fully rebalanced stake pool: + +```console +$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Preferred Deposit Validator: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk +Epoch Fee: 3/100 of epoch rewards +Withdrawal Fee: none +Stake Deposit Fee: none +SOL Deposit Fee: none +SOL Deposit Referral Fee: none +Stake Deposit Referral Fee: none +Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎10.006848640 +Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎40.000000000 Last Update Epoch: 8 +Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎40.000000000 Last Update Epoch: 8 +Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎40.000000000 Last Update Epoch: 8 +Total Pool Stake: ◎130.006848640 +Total Pool Tokens: 130.00684864 +Current Number of Validators: 3 +Max Number of Validators: 1000 +``` + +Due to staking rewards that accrued during the rebalancing process, the pool may +not perfectly balanced. This is completely normal. + +### Set Preferred Deposit / Withdraw Validator + +Since a stake pool accepts deposits to any of its stake accounts, and allows +withdrawals from any of its stake accounts, it could be used by malicious arbitrageurs +looking to maximize returns each epoch. + +For example, if a stake pool has 1000 validators, an arbitrageur could stake to +any one of those validators. At the end of the epoch, they can check which +validator has the best performance, deposit their stake, and immediately withdraw +from the highest performing validator. Once rewards are paid out, they can take +their valuable stake, and deposit it back for more than they had. + +To mitigate this arbitrage, a stake pool staker can set a preferred withdraw +or deposit validator. Any deposits or withdrawals must go to the corresponding +stake account, making this attack impossible without a lot of funds. + +Let's set a preferred deposit validator stake account: + +```console +$ spl-stake-pool set-preferred-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR deposit --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Signature: j6fbTqGJ8ehgKnSPns1adaSeFwg5M3wP1a32qYwZsQjymYoSejFUXLNGwvHSouJcFm4C78HUoC8xd7cvb5iActL +``` + +And then let's set the preferred withdraw validator stake account to the same one: + +```console +$ spl-stake-pool set-preferred-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR withdraw --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Signature: 4MKdYLyFqU6H3311YZDeLtsoeGZMzswBHyBCRjHfkzuN1rB4LXJbPfkgUGLKkdbsxJvPRub7SqB1zNPTqDdwti2w +``` + +At any time, they may also unset the preferred validator: + +```console +$ spl-stake-pool set-preferred-validator Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR withdraw --unset +Signature: 5Qh9FA3EXtJ7nKw7UyxmMWXnTMLRKQqcpvfEsEyBtxSPqzPAXp2vFXnPg1Pw8f37JFdvyzYay65CtA8Z1ewzVkvF +``` + +The preferred validators are marked in the `list` command: + +```console +$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Preferred Deposit Validator: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Preferred Withdraw Validator: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +... +``` + +## 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. + +```console +$ spl-stake-pool list Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Stake Pool: Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Pool Token Mint: BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Preferred Deposit Validator: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk +Epoch Fee: 3/100 of epoch rewards +Withdrawal Fee: none +Stake Deposit Fee: none +SOL Deposit Fee: none +SOL Deposit Referral Fee: none +Stake Deposit Referral Fee: none +Reserve Account: EN4px2h4gFkYtsQUi4yeCYBrdRM4DoRxCVJyavMXEAm5 Available Balance: ◎10.006848640 +Vote Account: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ Balance: ◎35.000000000 Last Update Epoch: 8 +Vote Account: J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H Balance: ◎35.000000000 Last Update Epoch: 8 +Vote Account: 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk Balance: ◎35.000000000 Last Update Epoch: 8 +Total Pool Stake: ◎115.006848640 +Total Pool Tokens: 115.00684864 +Current Number of Validators: 3 +Max Number of Validators: 1000 +``` + +### Deposit SOL + +Stake pools accept SOL deposits directly from a normal SOL wallet account, and +in exchange mint the appropriate amount of pool tokens. + +```console +$ spl-stake-pool deposit-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 100 +Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 23CptpZaq33njCpJPAvk8XS53xXwpfqF1sGxChk3VDB5mzz7XPKQqwsreun3iwZ6b51AyHqGBaUyc6tx9fqvF9JK +``` + +In return, the stake pool has minted us new pool tokens, representing our share +of ownership in the pool. We can double-check our stake pool account using the +SPL token command-line utility. + +```console +$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +100.00000000 +``` + +### Withdraw SOL + +Stake pools allow SOL withdrawals directly from the reserve and into a normal +SOL wallet account, and in exchange burns the provided pool tokens. + +```console +$ spl-stake-pool withdraw-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8 2 +Signature: 4bqZKUUrjVspqTGqGqX4zxnHnJB67WbeukKUZRmxJ2yFmr275CtHPjZNzQJD9Pe7Q6mSxnUpcVv9FUdAbGP9RyBc +``` + +The stake pool has burned 2 pool tokens, and in return, sent SOL to +`7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8`. + +You can check that the pool tokens have been burned: + +```console +$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +98.00000000 +``` + +And you can check that the recipient has been credited: + +```console +$ solana balance 7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8 +2 SOL +``` + +### Deposit stake + +Stake pools also accept deposits from active stake 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 +`38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk` is a valid vote account, so let's +create a stake account and delegate our stake there. + +```console +$ solana-keygen new --no-passphrase -o stake-account.json +Generating a new keypair +Wrote new keypair to stake-account.json +============================================================================ +pubkey: 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ +============================================================================ +Save this seed phrase to recover your new keypair: +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +============================================================================ +$ solana create-stake-account stake-account.json 10 +Signature: 5Y9r6MNoqJzVX8TWryAJbdp8i2DvintfxbYWoY6VcLEPgphK2tdydhtJTd3o3dF7QdM2Pg8sBFDZuyNcMag3nPvj +$ solana delegate-stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ 38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk +Signature: 2cDjHXSHjuadGQf1NQpPi43A8R19aCifsY16yTcictKPHcSAXN5TvXZ58nDJwkYs12tuZfTh5WVgAMSvptfrKdPP +``` + +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. + +```console +$ spl-stake-pool deposit-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ +Depositing stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ into stake pool account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt +Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 45x2UtA1b49eBPtRHdkvA3k8JneZzfwjptNN1kKQZaPABYiJ4hSA8qwi7qLNN5b3Fr4Z6vXhJprrTCpkk3f8UqgD +``` + +The CLI will default to using the fee payer's +[Associated Token Account](associated-token-account.md) for stake pool tokens +and the withdraw authority on the deposited stake account. + +Alternatively, you can create an SPL token account yourself and pass it as the +`token-receiver` for the command, and specify the withdraw authority on the +stake account using the `withdraw-authority` flag. + +```console +$ spl-stake-pool deposit-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ --token-receiver 34XMHa3JUPv46ftU4dGHvemZ9oKVjnciRePYMcX3rjEF --withdraw-authority authority.json +Depositing stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ into stake pool account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt +Signature: 4AESGZzqBVfj5xQnMiPWAwzJnAtQDRFK1Ha6jqKKTs46Zm5fw3LqgU1mRAT6CKTywVfFMHZCLm1hcQNScSMwVvjQ +``` + +In return, the stake pool has minted us new pool tokens, representing our share +of ownership in the pool. We can double-check our stake pool account using the +SPL token command-line utility. + +```console +$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +10.00000000 +``` + +#### Note on stake deposit fee + +Stake pools have separate fees for stake and SOL, so the total fee from depositing +a stake account is calculated from the rent-exempt reserve as SOL, and the delegation +as stake. + +For example, if a stake pool has a stake deposit fee of 1%, and a SOL deposit fee +of 5%, and you deposit a stake account with 10 SOL in stake, and .00228288 SOL +in rent-exemption, the total fee charged is: + +``` +total_fee = stake_delegation * stake_deposit_fee + rent_exemption * sol_deposit_fee +total_fee = 10 * 1% + .00228288 * 5% +total_fee = 0.100114144 +``` + +### Update + +Every epoch, the network pays out rewards to stake accounts managed by the stake +pool, increasing the value of pool 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. + +```console +$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Signature: 2rtPNGKFSSnXFCb6MKG5wHp34dkB5hJWNhro8EU2oGh1USafAgzu98EgoRnPLi7ojQfmTpvXk4S7DWXYGu5t85Ka +Signature: 5V2oCNvZCNJfC6QXHmR2UHGxVMip6nfZixYkVjFQBTyTf2Z9s9GJ9BjkxSFGvUsvW6zc2cCRv9Lqucu1cgHMFcVU +``` + +If another user already updated the stake pool balance for the current epoch, we +see a different output. + +```sh +$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR +Update not required +``` + +If no one updates the stake pool in the current epoch, all instructions, including +deposit and withdraw, will fail. The update instruction is permissionless, so any user +can run it before interacting with the pool. As a convenience, the CLI attempts +to update before running any instruction on the stake pool. + +If the stake pool transient stakes are in an unexpected state, and merges are +not possible, there is the option to only update the stake pool balances without +performing merges using the `--no-merge` flag. + +```sh +$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --no-merge +Signature: 5cjdZG727uzwnEEG3vJ1vskA9WsXibaEHh7imXSb2S1cwEYK4Q3btr2GEeAV8EffK4CEQ2WM6PQxawkJAHoZ4jsQ +Signature: EBHbSRstJ3HxKwYKak8vEwVMKr1UBxdbqs5KuX3XYt4ppPjhaziGEtvL2TJCm1HLokbrtMeTEv57Ef4xhByJtJP +``` + +Later on, whenever the transient stakes are ready to be merged, it is possible to +force another update in the same epoch using the `--force` flag. + +```sh +$ spl-stake-pool update Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --force +Signature: 5RneEBwJkFytBJaJdkvCTHFrG3QzE3SGf9vdBm9gteCcHV4HwaHzj3mjX1hZg4yCREQSgmo3H9bPF6auMmMFTSTo +Signature: 1215wJUY7vj82TQoGCacQ2VJZ157HnCTvfsUXkYph3nZzJNmeDaGmy1nCD7hkhFfxnQYYxVtec5TkDFGGB4e7EvG +``` + +### Withdraw stake + +Whenever the user wants to recover their SOL plus accrued rewards, they can provide their +pool tokens in exchange for an activated stake account. + +Let's withdraw active staked SOL in exchange for 5 pool tokens. + +```console +$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 +Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Creating account to receive stake 5GuAyPAt6577HoGhSVRNBv6aHohVtjQ8q7q5i3X1p4tB +Signature: 5fzaKt5MU8bLjJRgNZyEktKsgweSQzFRpubCGKPeuk9shNQb4CtTkbgZ2X5MmC1VRDZ3YcCTPdtL9sFpXYfoqaeV +``` + +The stake pool took 5 pool tokens, and in exchange the user received a fully +active stake account, delegated to `EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ`. +Let's double-check the status of the stake account: + +```console +$ solana stake-account 5GuAyPAt6577HoGhSVRNBv6aHohVtjQ8q7q5i3X1p4tB +Balance: 5.00228288 SOL +Rent Exempt Reserve: 0.00228288 SOL +Delegated Stake: 5 SOL +Active Stake: 5 SOL +Delegated Vote Account Address: EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Stake Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Withdraw Authority: 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +``` + +Note: this operation cost the user some funds, as they needed to create a new +stake account with the minimum rent exemption in order to receive the funds. This +allows the user to withdraw any amount of stake pool tokens, even if it is not +enough to cover the stake account rent-exemption. + +Alternatively, the user can specify an existing uninitialized stake account to +receive their stake using the `--stake-receiver` parameter. + +```console +$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --amount 0.02 --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ --stake-receiver CZF2z3JJoDmJRcVjtsrz1BKUUGNL3VPW5FPFqge1bzmQ +Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Signature: 2xBPVPJ749AE4hHNCNYdjuHv1EdMvxm9uvvraWfTA7Urrvecwh9w64URCyLLroLQ2RKDGE2QELM2ZHd8qRkjavJM +``` + +By default, the withdraw command uses the `token-owner`'s associated token account to +source the pool tokens. It's possible to specify the SPL token account using +the `--pool-account` flag. + +```console +$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 --pool-account 34XMHa3JUPv46ftU4dGHvemZ9oKVjnciRePYMcX3rjEF +Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Creating account to receive stake CZF2z3JJoDmJRcVjtsrz1BKUUGNL3VPW5FPFqge1bzmQ +Signature: 2xBPVPJ749AE4hHNCNYdjuHv1EdMvxm9uvvraWfTA7Urrvecwh9w64URCyLLroLQ2RKDGE2QELM2ZHd8qRkjavJM +``` + +By default, the withdraw command will withdraw from the largest validator stake +accounts in the pool. It's also possible to specify a specific vote account for +the withdraw using the `--vote-account` flag. + +```console +$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR --amount 5 --vote-account EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Withdrawing ◎5.000000000, or 5 pool tokens, from stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Creating account to receive stake CZF2z3JJoDmJRcVjtsrz1BKUUGNL3VPW5FPFqge1bzmQ +Signature: 2xBPVPJ749AE4hHNCNYdjuHv1EdMvxm9uvvraWfTA7Urrvecwh9w64URCyLLroLQ2RKDGE2QELM2ZHd8qRkjavJM +``` + +Note that the associated validator stake account must have enough lamports to +satisfy the pool token amount requested. + +#### Special case: exiting pool with a delinquent staker + +With the reserve stake, it's possible for a delinquent or malicious staker to +move all stake into the reserve through `decrease-validator-stake`, so the +pool tokens will not gain rewards, and the stake pool users will not +be able to withdraw their funds. + +To get around this case, it is also possible to withdraw from the stake pool's +reserve, but only if all of the validator stake accounts are at the minimum amount of +`0.001 SOL + stake account rent exemption`. + +```console +$ spl-stake-pool withdraw-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 5 --use-reserve +Withdrawing ◎5.000000000, or 5 pool tokens, from stake account J5XB7mWpeaUZxZ6ogXT57qSCobczx27vLZYSgfSbZoBB +Creating account to receive stake 51XdXiBSsVzeuY79xJwWAGZgeKzzgFKWajkwvWyrRiNE +Signature: yQH9n7Go6iCMEYXqWef38ZYBPwXDmbwKAJFJ4EHD6TusBpusKsfNuT3TV9TL8FmxR2N9ExZTZwbD9Njc3rMvUcf +``` diff --git a/docs/src/stake-pool/overview.md b/docs/src/stake-pool/overview.md new file mode 100644 index 00000000000..23f44efd0ba --- /dev/null +++ b/docs/src/stake-pool/overview.md @@ -0,0 +1,271 @@ +--- +title: Operation +--- + +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. + +## Staking + +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). + +Additional information regarding staking and stake programming is available at: + +- https://solana.com/staking +- https://docs.solana.com/staking/stake-programming + +## Background + +Solana's programming model and the definitions of the Solana terms used in this +document are available at: + +- https://docs.solana.com/apps +- https://docs.solana.com/terminology + +## 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 validators +* user: provides staked SOL into an existing stake pool + +In its current iteration, the stake pool accepts active stakes or SOL, so +deposits may come from either an active stake or SOL wallet. Withdrawals +can return a fully active stake account from one of the stake pool's accounts, +or SOL from the reserve. + +This means that stake pool managers and stakers 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: + +- https://docs.solana.com/cli/delegate-stake +- https://docs.solana.com/cli/manage-stake-accounts + +To reach a wider audience of users, stake pool managers are encouraged +to provide a market for their pool's tokens, through an AMM +like [Token Swap](../token-swap.md). + +Alternatively, stake pool managers can partner with wallet and stake account +providers for direct SOL deposits. + +## Operation + +A stake pool manager creates a stake pool, and the staker includes validators that will +receive delegations from the pool by adding "validator stake accounts" to the pool +using the `add-validator` instruction. In this command, the stake pool creates +a new stake account and delegates it to the desired validator. + +At this point, users can participate with deposits. They can directly deposit +SOL into the stake pool using the `deposit-sol` instruction. Within this instruction, +the stake pool will move SOL into the pool's reserve account, to be redistributed +by the staker. + +Alternatively, users can deposit a stake account into the pool. To do this, +they must delegate a stake account to the one of the validators in the stake pool. +If the stake pool has a preferred deposit validator, the user must delegate their +stake to that validator's vote account. + +Once the stake becomes active, which happens at the following epoch boundary +(maximum 2 days), the user can deposit their stake into the pool using the +`deposit-stake` instruction. + +In exchange for their deposit (SOL or stake), the user receives SPL tokens +representing their fractional ownership in pool. A percentage of the rewards +earned by the pool goes to the pool manager as an epoch fee. + +Over time, as the stakes in the pool accrue rewards, the user's fractional +ownership will be worth more than their initial deposit. + +Whenever they wish to exit the pool, the user may use the `withdraw-sol` instruction +to receive SOL from the stake pool's reserve in exchange for stake pool tokens. +Note that this operation will fail if there is not enough SOL in the stake pool's +reserve, which is normal if the stake pool manager stakes all of the SOL in the pool. + +Alternatively, they can use the `withdraw-stake` instruction to withdraw an +activated stake account in exchange for their SPL pool tokens. The user will get +back a SOL stake account immediately. The ability to withdraw stake is always +possible, under all circumstances. + +Note: when withdrawing stake, if the user wants to withdraw the SOL in the stake +account, they must first deactivate the stake account and wait until the next +epoch boundary (maximum 2 days). Once the stake is inactive, they can freely +withdraw the SOL. + +The stake pool staker can add and remove validators, or rebalance the pool by +decreasing the stake on a validator, waiting an epoch to move it into the stake +pool's reserve account, then increasing the stake on another validator. + +The staker operation to add a new validator requires 0.00328288 SOL to create +the stake account on a validator, so the stake pool staker will need liquidity +on hand to fully manage the pool stakes. The SOL used to add a new validator +is recovered when removing the validator. + +### Fees + +The stake pool program provides managers many options for making the pool +financially viable, predominantly through fees. There are five different sources +of fees: + +* Epoch: every epoch (roughly 2 days), the stake accounts in the pool earn + inflation rewards, so the stake pool mints pool tokens into the manager's fee + account as a proportion of the earned rewards. For example, if the pool earns + 10 SOL in rewards, and the fee is set to 2%, the manager will earn pool tokens + worth 0.2 SOL. +* SOL withdraw: sends a proportion of the desired withdrawal amount to the manager + For example, if a user wishes to withdraw 100 pool tokens, and the fee is set + to 3%, 3 pool tokens go to the manager, and the remaining 97 tokens go to the + user in the form of a SOL. +* Stake withdraw: sends a proportion of the desired withdrawal amount to the manager + before creating a new stake for the user. +* SOL deposit: converts the entire SOL deposit into pool tokens, then sends a + proportion of those to the manager, and the rest to the user +* Stake deposit: converts the stake account's delegation plus rent-exemption + to pool tokens, sends a proportion of those to the manager, and the rest to + the user + +For partner applications, there's the option of a referral fee on deposits. +During SOL or stake deposits, the stake pool can redistribute a percentage of +the fees to another address as a referral fee. + +This option is particularly attractive for wallet providers. When a wallet +integrates a stake pool, the wallet developer will have the option to earn +additional tokens anytime a user deposits into the stake pool. Stake pool +managers can use this feature to create strategic partnerships and entice +greater adoption of stake pools! + +### Funding restrictions + +To give the manager more control over funds entering the pool, stake pools allow +deposit and withdrawal restrictions on SOL and stakes through three different +"funding authorities": + +* SOL deposit +* Stake deposit +* SOL withdrawal + +If the field is set, that authority must sign the associated instruction. + +For example, if the manager sets a stake deposit authority, then that address +must sign every stake deposit instruction. + +This can also be useful in a few situations: + +* Control who deposits into the stake pool +* Prohibit a form of deposit. For example, the manager only wishes to have SOL + deposits, so they set a stake deposit authority, making it only possible to + deposit a stake account if that authority signs the transaction. +* Maintenance mode. If the pool needs time to reset fees or otherwise, the + manager can temporarily restrict new deposits by setting deposit authorities. + +Note: in order to keep user funds safe, stake withdrawals are always permitted. + +## Security Audits + +Multiple security firms have audited the stake pool program to ensure total +safety of funds. The audit reports are available for reading, presented in descending +chronological order, and the commit hash that each was reviewed at: + +* Quantstamp + - Initial review commit hash [`99914c9`](https://github.com/solana-labs/solana-program-library/tree/99914c9fc7246b22ef04416586ab1722c89576de) + - Re-review commit hash [`3b48fa0`](https://github.com/solana-labs/solana-program-library/tree/3b48fa09d38d1b66ffb4fef186b606f1bc4fdb31) + - Final report https://solana.com/SolanaQuantstampStakePoolAudit.pdf +* Neodyme + - Review commit hash [`0a85a9a`](https://github.com/solana-labs/solana-program-library/tree/0a85a9a533795b6338ea144e433893c6c0056210) + - Report https://solana.com/SolanaNeodymeStakePoolAudit.pdf +* Kudelski + - Review commit hash [`3dd6767`](https://github.com/solana-labs/solana-program-library/tree/3dd67672974f92d3b648bb50ee74f4747a5f8973) + - Report https://solana.com/SolanaKudelskiStakePoolAudit.pdf + +## Safety of Funds + +One of the primary aims of the stake pool program is to always allow pool token +holders to withdraw their funds at any time. + +To that end, let's look at the three classes of stake accounts in the stake pool system: + +* validator stake: active stake accounts, one per validator in the pool +* transient stake: activating or deactivating stake accounts, merged into the reserve after deactivation, or into the validator stake after activation, one per validator +* reserve stake: inactive stake, to be used by the staker for rebalancing + +Additionally, the staker may set a "preferred withdraw account", which forces users +to withdraw from a particular stake account. This is to prevent malicious +depositors from using the stake pool as a free conversion between validators. + +When processing withdrawals, the order of priority goes: + +* preferred withdraw validator stake account (if set) +* validator stake accounts +* transient stake accounts +* reserve stake account + +If there is preferred withdraw validator, and that validator stake account has +any SOL, a user must withdraw from that account. + +If that account is empty, or the preferred withdraw validator stake account is +not set, then the user must withdraw from any validator stake account. + +If all validator stake accounts are empty, which may happen if the stake pool +staker decreases the stake on all validators at once, then the user must withdraw +from any transient stake account. + +If all transient stake accounts are empty, then the user must withdraw from the +reserve. + +In this way, a user's funds are never at risk, and always redeemable. + +## Appendix + +### Active stakes + +As mentioned earlier, the stake pool works with active stakes to +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. + +### Transient stake accounts + +Each validator gets one transient stake account, so the staker can only +perform one action at a time on a validator. It's impossible to increase +and decrease the stake on a validator at the same time. The staker must wait for +the existing transient stake account to get merged during an `update` instruction +before performing a new action. + +### Reserve stake account + +Every stake pool is initialized with an undelegated reserve stake account, used +to hold undelegated stake in process of rebalancing. After the staker decreases +the stake on a validator, one epoch later, the update operation will merge the +decreased stake into the reserve. Conversely, whenever the staker increases the +stake on a validator, the lamports are drawn from the reserve stake account. + +### Validator list account + +Every stake pool contains two data accounts: the stake pool and the validator list. + +The stake pool contains overall information about the pool, including fees, +pool token mint, amount under management, etc. + +The validator list contains specific information about each of the validator +stake accounts in the pool. This information includes the amount of SOL staked on +the validator by the pool, and the amount of SOL being activated / deactivated +on the validator. + +Every stake pool must have its own validator list account, otherwise it will +fail on initialization. + +### 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. diff --git a/docs/src/stake-pool/quickstart.md b/docs/src/stake-pool/quickstart.md new file mode 100644 index 00000000000..54b036b2f24 --- /dev/null +++ b/docs/src/stake-pool/quickstart.md @@ -0,0 +1,223 @@ +--- +title: Quick Start Guide +--- + +This quick start guide is meant for managers who want to start running a pool +right away. + +## Prerequisites + +This guide requires the Solana CLI tool suite and Stake Pool CLI tool. + +- [Install the Solana Tools](https://docs.solana.com/cli/install-solana-cli-tools) +- [Install the Stake Pool CLI](cli.md) + +You must also have an account with SOL. The guide will assume that you +are using the default keypair created at the default location using `solana-keygen new`. +Note that it is possible to override the default keypair with every command if +needed. + +If you are running on localhost using `solana-test-validator`, the default keypair +will automatically start with 500,000,000 SOL. + +If you are running on devnet or testnet, you can airdrop funds using `solana airdrop 1`. + +If you are running on mainnet-beta, you must purchase funds some other way, from +an exchange, a friend, etc. + +## Sample scripts + +This guide uses the +[sample scripts on GitHub](https://github.com/solana-labs/solana-program-library/tree/master/stake-pool/cli/scripts) +to run everything quickly and easily. + +You'll see the following scripts: + +* `setup-test-validator.sh`: sets up a local test validator with validator vote accounts +* `setup-stake-pool.sh`: creates a new stake pool with hardcoded parameters +* `add-validators.sh`: adds validators to the stake pool +* `deposit.sh`: performs stake and SOL deposits +* `rebalance.sh`: rebalances the stake pool +* `withdraw.sh`: performs some withdrawals + +This guide will use most of these scripts to setup a stake pool on a local +network. + +## (Optional) Step 0: Setup a local network for testing + +All of these scripts can be run against devnet, testnet, or mainnet-beta, but +to allow for more experimentation, we will setup a local validator with some +validator vote accounts using `setup-test-validator.sh`. + +The script accepts the number of vote accounts to create and file path to output +validator vote accounts, e.g.: + +```bash +$ ./setup-test-validator.sh 10 local_validators.txt +``` + +This will take roughly 10 seconds, eventually outputting a file with list of +base58-encoded public keys. These represent validator vote accounts on the +local network, e.g.: + +``` +EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +J3xu64PWShcMen99kU3igxtwbke2Nwfo8pkZNRgrq66H +38DYMkwYCvsj8TC6cNaEvFHHVDYeWDp1qUgMgyjNqZXk +7q371UZcYJTMmFPeijUJ6RBr6jHE9t4mDd2gnDs7wpje +7ffftyketRJrmCcczhSnWatxB32SzAG3dhDpnyRdm91d +HtqJXQNWr4E1qxftAxxqNnHbpSYnokayHSxurzS9vKKF +4e6EmSSmExdRM6tF1osYiAq9HxXN5oVvDqS78FcT6F4P +DrT6VGqqJT1GRVaZmuEjNim4ie7ecmNixjiycd67jyJy +71vNo5HBuAtejbcQYp9CdBeT7npVdbJqjmuWbXbNeudq +7FMebvnWnWN45KF5Fa3Y7kAJZReKU6WLzribtWDJybax +``` + +Note: this will fail if another `solana-test-validator` is already running. + +#### Important notes on local network + +If you are using epochs of 32 slots, there is a good chance +that you will pass an epoch while using one of the stake pool commands, causing +it to fail with: `Custom program error: 0x11`. This is totally normal, and will +not happen on the other networks. You simply need to re-run the command. + +Since there is no voting activity on the test validator network, you will +need to use the secret `--force` flag with `solana delegate-stake`, ie: + +```bash +$ solana delegate-stake --force stake.json CzDy6uxLTko5Jjcdm46AozMmrARY6R2aDBagdemiBuiT +``` + +## Step 1: Create the stake pool + +Our next script is `setup-stake-pool.sh`. In it, you will see a large section +in which you can modify parameters for your stake pool. These parameters are used +to create a new stake pool, and include: + +* epoch fee, expressed as two different flags, numerator and denominator +* withdrawal fee, expressed as two different flags, numerator and denominator +* deposit fee, expressed as two different flags, numerator and denominator +* referral fee, expressed as a number between 0 and 100, inclusive +* maximum number of validators (highest possible is 3,950 currently) +* (Optional) deposit authority, for restricted pools + +Although fees may seem uninteresting or scammy at this point, consider the costs +of running your stake pool, and potential malicious actors that may abuse your pool +if it has no fees. + +Each of these parameters is modifiable after pool creation, so there's no need +to worry about being locked in to any choices. + +Modify the parameters to suit your needs. In our example, we will use fees +of 0.3%, a referral fee of 50%, opt to *not* set a deposit authority, and have +the maximum number of validators (3,950). Next, run the script: + +```bash +$ ./setup-stake-pool.sh +Creating pool ++ spl-stake-pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 1000 --withdrawal-fee-numerator 3 --withdrawal-fee-denominator 1000 --deposit-fee-numerator 3 --deposit-fee-denominator 1000 --referral-fee 50 --max-validators 3950 --pool-keypair keys/stake-pool.json --validator-list-keypair keys/validator-list.json --mint-keypair keys/mint.json --reserve-keypair keys/reserve.json +Creating reserve stake 4tvTkLB4X7ahUYZ2NaTohkG3mud4UBBvu9ZEGD4Wk9mt +Creating mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB +Creating associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Creating pool fee collection account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ +Signature: 51yf2J6dSGAx42KPs2oTMTV4ufEm1ncAHyLPQ6PNf4sbeMHGqno7BGn2tHkUnrd7PRXiWBbGzCWpJNevYjmoLgn2 +Creating stake pool Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR with validator list 86VZZCuqiz7sDJpFKjQy9c9dZQN9vwDKbYgY8pcwHuaF +Signature: 47QHcWMEa5Syg13C3SQRA4n88Y8iLx1f39wJXQAStRUxpt2VD5t6pYgAdruNRHUQt1ZBY8QwbvEC1LX9j3nPrAzn +``` + +Your stake pool now exists! For the largest number of validators, the cost for +this phase is ~2.02 SOL. + +## Step 2: Add validators to the pool + +Now that the pool exists, we need to add validators to it. + +Using `add-validators.sh`, we'll add each of the validators created during step 0 +to the stake pool. If you are running on another network, you can create your own +file with validator vote accounts. + +```bash +$ ./add-validators.sh keys/stake-pool.json local_validators.txt +Adding validator stake accounts to the pool +Adding stake account 3k7Nwu9jUSc6SNG11wzufKYoZXRFgxWamheGLYWp5Rvx, delegated to EhRbKi4Vhm1oUCGWHiLEMYZqDrHwEd7Jgzgi26QJKvfQ +Signature: 5Vm2n3umPXFzQgDiaib1B42k7GqsNYHZWrauoe4DUyFszczB7Hjv9r1DKWKrypc8KDiUccdWmJhHBqM1fdP6WiCm +Signature: 3XtmYu9msqnMeKJs9BopYjn5QTc5hENMXXiBwvEw6HYzU5w6z1HUkGwNW24io4Vu9WRKFFN6SAtrfkZBLK4fYjv4 +... (something similar repeated 9 more times) +``` + +This operation costs 0.00328288 SOL per validator. This amount is totally recoverable +by removing the validator from the stake pool. + +## Step 3: Deposit into the pool + +Now that your pool has validators, it needs some SOL or stake accounts for you +to manage. There are two possible sources of deposits: SOL or stake accounts. + +### a) Depositing SOL + +This will likely be the most attractive form of deposit, since it's the easiest +for everyone to use. Normally, this will likely be done from a DeFi app or +wallet, but in our example, we'll do it straight from the command line. Let's +deposit 10 SOL into our pool: + +``` +$ spl-stake-pool deposit-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 100 +Using existing associated token account DgyZrAq88bnG1TNRxpgDQzWXpzEurCvfY2ukKFWBvADQ to receive stake pool tokens of mint BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB, owned by 4SnSuUtJGKvk2GYpBwmEsWG53zTurVM8yXGsoiZQyMJn +Signature: 4AJv6hSznYoMGnaQvjWXSBjKqtjYpjBx2MLezmRRjWRDa8vUaBLQfPNGd3kamZNs1JeWSvnzczwtzsMD5WkgKamA +``` + +Now there will be some SOL for us to work with. + +### b) Depositing stake accounts + +Alternatively, users can deposit stake accounts into the pool. This option is +particularly attractive for users that already have a stake account, and either +want stake pool tokens in return, or to diversify their stake more. + +The `deposit.sh` script gives an idea of how this works with the CLI. + +Creates new stakes to deposit a given amount into each of the stake accounts in +the pool, given the stake pool and validator file. + +```bash +$ ./deposit.sh keys/stake-pool.json local_validators.txt 10 +``` + +Note: This is a bit more finnicky on a local network because of the short epochs, and +may fail. No problem, you simply need to retry. + +## Step 4: Rebalance stake in the pool + +Over time, as people deposit SOL into the reserve, or as validator performance +varies, you will want to move stake around. The best way to do this will be +through an automated system to collect information about the stake pool and the +network, and decide how much stake to allocate to each validator. + +The Solana Foundation maintains an open-source bot for its delegation program, +which can be adapated for your stake pool. The source code is part of the +[stake-o-matic GitHub repo](https://github.com/solana-labs/stake-o-matic/tree/master/bot). + +Additionally, there is a work-in-progress Python stake pool bot, found at the +[stake-pool-py on GitHub](https://github.com/solana-labs/solana-program-library/tree/master/stake-pool/py). + +For our example, we will run a simple pool rebalancer, which increases the stake +on each validator in the list by the given amount. There are no checks or logic +to make sure that this is valid. + +```bash +$ ./rebalance.sh keys/stake-pool.json local_validators.txt 1 +``` + +## Step 5: Withdraw from the stake pool + +Finally, if a user wants to withdraw from the stake pool, they can choose to +withdraw SOL from the reserve if it has enough SOL, or to withdraw from one of +the stake accounts in the pool. + +The `withdraw.sh` script removes stakes and SOL from each of the stake accounts +in the pool, given the stake pool, validator file, and amount. + +```bash +$ ./withdraw.sh keys/stake-pool.json local_validators.txt 1 +``` diff --git a/stake-pool/cli/README.md b/stake-pool/cli/README.md index 36f57c2838c..b3ed9f3ff84 100644 --- a/stake-pool/cli/README.md +++ b/stake-pool/cli/README.md @@ -2,68 +2,6 @@ A basic command-line for creating and using SPL Stake Pools. See https://spl.solana.com/stake-pool for more details. -## Scripts for setting up a stake pool - -Under `./scripts`, this repo also contains some bash scripts that are useful for -setting up your own stake pool. These scripts require the Solana CLI tool suite, -which can be downloaded by following the instructions at -(https://docs.solana.com/cli/install-solana-cli-tools). Additionally, you must -have a usable keypair, created at the default location using `solana-keygen new`. - -### setup-local.sh - -Builds the stake pool program and sets up a `solana-test-validator` with some -new validator vote accounts. - -It accepts the number of vote accounts to create and validator list file path to output -vote accounts, e.g.: - -```bash -$ ./setup-local.sh 100 validator_list.txt -``` - -#### Important notes on local network - -If you are using epochs of 32 slots, there is a good chance -that you will pass an epoch while using one of the stake pool commands, causing -it to fail with: `Custom program error: 0x11`. This is totally normal, and will -not happen on a normal network. - -Since there is no voting activity on the test validator network, you will -need to use the `--force` flag with `solana delegate-stake`, ie: - -```bash -$ solana delegate-stake --force stake.json CzDy6uxLTko5Jjcdm46AozMmrARY6R2aDBagdemiBuiT -``` - -### setup-stake-pool.sh - -Creates a new stake pool with the parameters hardcoded in the script: - -* epoch fee numerator -* epoch fee denominator -* withdrawal fee numerator -* withdrawal fee denominator -* deposit fee numerator -* deposit fee denominator -* referral fee -* manager -* staker -* maximum number of validators -* list of validator vote accounts -* (Optional) deposit authority, for restricted pools - -Modify the parameters to suit your needs, and your pool will be created! - -```bash -$ ./setup-stake-pool.sh -``` - -### deposit-withdraw.sh - -Creates new stakes to deposit into each of the stake accounts in the pool, given -the stake pool, mint, and validator list. - -```bash -$ ./deposit-withdraw.sh keys/stake-pool.json validator_list.txt -``` +Under `./scripts`, there are helpful Bash scripts for setting up and running a +stake pool. More information at the +[stake pool quick start guide](https://spl.solana.com/stake-pool/quickstart). diff --git a/stake-pool/cli/scripts/add-validators.sh b/stake-pool/cli/scripts/add-validators.sh new file mode 100755 index 00000000000..4bdcbdf1e1e --- /dev/null +++ b/stake-pool/cli/scripts/add-validators.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Script to add new validators to a stake pool, given the stake pool keyfile and +# a file listing validator vote account pubkeys + +cd "$(dirname "$0")" || exit +stake_pool_keyfile=$1 +validator_list=$2 # File containing validator vote account addresses, each will be added to the stake pool after creation + +add_validator_stakes () { + stake_pool=$1 + validator_list=$2 + while read -r validator + do + $spl_stake_pool add-validator "$stake_pool" "$validator" + done < "$validator_list" +} + +spl_stake_pool=spl-stake-pool +# Uncomment to use a local build +#spl_stake_pool=../../../target/debug/spl-stake-pool + +stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") +echo "Adding validator stake accounts to the pool" +add_validator_stakes "$stake_pool_pubkey" "$validator_list" diff --git a/stake-pool/cli/scripts/deposit-withdraw.sh b/stake-pool/cli/scripts/deposit-withdraw.sh deleted file mode 100755 index 0781aae56c1..00000000000 --- a/stake-pool/cli/scripts/deposit-withdraw.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bash - -# Script to deposit and withdraw stakes from a pool, given stake pool public key -# and a path to a file containing a list of validator vote accounts - -cd "$(dirname "$0")" -stake_pool_keyfile=$1 -validator_list=$2 - -create_keypair () { - if test ! -f $1 - then - solana-keygen new --no-passphrase -s -o $1 - fi -} - -create_user_stakes () { - validator_list=$1 - sol_amount=$2 - authority=$3 - for validator in $(cat $validator_list) - do - create_keypair $keys_dir/stake_$validator.json - solana create-stake-account $keys_dir/stake_$validator.json $sol_amount --withdraw-authority $authority --stake-authority $authority - done -} - -delegate_user_stakes () { - validator_list=$1 - authority=$2 - for validator in $(cat $validator_list) - do - solana delegate-stake --force $keys_dir/stake_$validator.json $validator --stake-authority $authority - done -} - -deposit_stakes () { - stake_pool_pubkey=$1 - validator_list=$2 - authority=$3 - for validator in $(cat $validator_list) - do - stake=$(solana-keygen pubkey $keys_dir/stake_$validator.json) - $spl_stake_pool deposit-stake $stake_pool_pubkey $stake --withdraw-authority $authority - done -} - -withdraw_stakes () { - stake_pool_pubkey=$1 - validator_list=$2 - pool_amount=$3 - for validator in $(cat $validator_list) - do - $spl_stake_pool withdraw-stake $stake_pool_pubkey $pool_amount --vote-account $validator - done -} - -sol_amount=2 -half_sol_amount=1 -keys_dir=keys -spl_stake_pool=../../../target/debug/spl-stake-pool -stake_pool_pubkey=$(solana-keygen pubkey $stake_pool_keyfile) -echo "Setting up keys directory $keys_dir" -mkdir -p $keys_dir -authority=$keys_dir/authority.json -echo "Setting up authority for deposited stake accounts at $authority" -create_keypair $authority - -echo "Creating user stake accounts to deposit into the pool" -create_user_stakes $validator_list $sol_amount $authority -echo "Delegating user stakes so that deposit will work" -delegate_user_stakes $validator_list $authority -echo "Waiting for stakes to activate, this may take awhile depending on the network!" -echo "If you are running on localnet with 32 slots per epoch, wait 12 seconds..." -sleep 12 -echo "Depositing stakes into stake pool" -deposit_stakes $stake_pool_pubkey $validator_list $authority -echo "Withdrawing stakes from stake pool" -withdraw_stakes $stake_pool_pubkey $validator_list $half_sol_amount -echo "Depositing SOL into stake pool to authority" -$spl_stake_pool deposit-sol $stake_pool_pubkey $sol_amount -echo "Withdrawing SOL from stake pool to authority" -$spl_stake_pool withdraw-sol $stake_pool_pubkey $authority $half_sol_amount diff --git a/stake-pool/cli/scripts/deposit.sh b/stake-pool/cli/scripts/deposit.sh new file mode 100755 index 00000000000..9f316f35349 --- /dev/null +++ b/stake-pool/cli/scripts/deposit.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# Script to deposit stakes and SOL into a stake pool, given the stake pool keyfile +# and a path to a file containing a list of validator vote accounts + +cd "$(dirname "$0")" || exit +stake_pool_keyfile=$1 +validator_list=$2 +sol_amount=$3 + +create_keypair () { + if test ! -f "$1" + then + solana-keygen new --no-passphrase -s -o "$1" + fi +} + +create_user_stakes () { + validator_list=$1 + sol_amount=$2 + authority=$3 + while read -r validator + do + create_keypair "$keys_dir/stake_$validator".json + solana create-stake-account "$keys_dir/stake_$validator.json" "$sol_amount" --withdraw-authority "$authority" --stake-authority "$authority" + done < "$validator_list" +} + +delegate_user_stakes () { + validator_list=$1 + authority=$2 + while read -r validator + do + solana delegate-stake --force "$keys_dir/stake_$validator.json" "$validator" --stake-authority "$authority" + done < "$validator_list" +} + +deposit_stakes () { + stake_pool_pubkey=$1 + validator_list=$2 + authority=$3 + while read -r validator + do + stake=$(solana-keygen pubkey "$keys_dir/stake_$validator.json") + $spl_stake_pool deposit-stake "$stake_pool_pubkey" "$stake" --withdraw-authority "$authority" + done < "$validator_list" +} + +keys_dir=keys +stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") + +spl_stake_pool=spl-stake-pool +# Uncomment to use a locally build CLI +#spl_stake_pool=../../../target/debug/spl-stake-pool + +echo "Setting up keys directory $keys_dir" +mkdir -p $keys_dir +authority=$keys_dir/authority.json +echo "Setting up authority for deposited stake accounts at $authority" +create_keypair $authority + +echo "Creating user stake accounts to deposit into the pool" +create_user_stakes "$validator_list" "$sol_amount" $authority +echo "Delegating user stakes so that deposit will work" +delegate_user_stakes "$validator_list" $authority + +echo "Waiting for stakes to activate, this may take awhile depending on the network!" +echo "If you are running on localnet with 32 slots per epoch, wait 12 seconds..." +sleep 12 +echo "Depositing stakes into stake pool" +deposit_stakes "$stake_pool_pubkey" "$validator_list" $authority +echo "Depositing SOL into stake pool" +$spl_stake_pool deposit-sol "$stake_pool_pubkey" "$sol_amount" diff --git a/stake-pool/cli/scripts/rebalance.sh b/stake-pool/cli/scripts/rebalance.sh new file mode 100755 index 00000000000..3db44972227 --- /dev/null +++ b/stake-pool/cli/scripts/rebalance.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Script to add a certain amount of SOL into a stake pool, given the stake pool +# keyfile and a path to a file containing a list of validator vote accounts + +cd "$(dirname "$0")" || exit +stake_pool_keyfile=$1 +validator_list=$2 +sol_amount=$3 + +spl_stake_pool=spl-stake-pool +# Uncomment to use a locally build CLI +#spl_stake_pool=../../../target/debug/spl-stake-pool + +increase_stakes () { + stake_pool_pubkey=$1 + validator_list=$2 + sol_amount=$3 + while read -r validator + do + $spl_stake_pool increase-validator-stake "$stake_pool_pubkey" "$validator" "$sol_amount" + done < "$validator_list" +} + +stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") +echo "Increasing amount delegated to each validator in stake pool" +increase_stakes "$stake_pool_pubkey" "$validator_list" "$sol_amount" diff --git a/stake-pool/cli/scripts/setup-local.sh b/stake-pool/cli/scripts/setup-local.sh deleted file mode 100755 index 70e019a1d5f..00000000000 --- a/stake-pool/cli/scripts/setup-local.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash - -# Script to setup a local solana-test-validator with the stake pool program -# given a maximum number of validators and a file path to store the list of -# test validator vote accounts. - -cd "$(dirname "$0")" -max_validators=$1 -validator_list=$2 - -create_keypair () { - if test ! -f $1 - then - solana-keygen new --no-passphrase -s -o $1 - fi -} - -build_stake_pool_program () { - cargo build-bpf --manifest-path ../../program/Cargo.toml -} - -setup_test_validator() { - solana-test-validator --bpf-program SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy ../../../target/deploy/spl_stake_pool.so --quiet --reset --slots-per-epoch 32 & - pid=$! - solana config set --url http://127.0.0.1:8899 - solana config set --commitment confirmed - echo "waiting for solana-test-validator, pid: $pid" - sleep 5 -} - -create_vote_accounts () { - max_validators=$1 - validator_list=$2 - for number in $(seq 1 $max_validators) - do - create_keypair $keys_dir/identity_$number.json - create_keypair $keys_dir/vote_$number.json - create_keypair $keys_dir/withdrawer_$number.json - solana create-vote-account $keys_dir/vote_$number.json $keys_dir/identity_$number.json $keys_dir/withdrawer_$number.json --commission 1 - vote_pubkey=$(solana-keygen pubkey $keys_dir/vote_$number.json) - echo $vote_pubkey >> $validator_list - done -} - - -echo "Setup keys directory and clear old validator list file if found" -keys_dir=keys -mkdir -p $keys_dir -if test -f $validator_list -then - rm $validator_list -fi - -echo "Building on-chain stake pool program" -build_stake_pool_program - -echo "Setting up local test validator" -setup_test_validator - -echo "Creating vote accounts, these accounts be added to the stake pool" -create_vote_accounts $max_validators $validator_list diff --git a/stake-pool/cli/scripts/setup-stake-pool.sh b/stake-pool/cli/scripts/setup-stake-pool.sh index 58a34fd4b07..e9bb2baf33d 100755 --- a/stake-pool/cli/scripts/setup-stake-pool.sh +++ b/stake-pool/cli/scripts/setup-stake-pool.sh @@ -1,18 +1,15 @@ #!/usr/bin/env bash -# Script to setup a stake pool, add new validators from a list +# Script to setup a stake pool from scratch. Please modify the parameters to +# create a stake pool to your liking! -cd "$(dirname "$0")" -global_args=() +cd "$(dirname "$0")" || exit command_args=() ################################################### ### MODIFY PARAMETERS BELOW THIS LINE FOR YOUR POOL ################################################### -global_args+=( --manager keys/new_manager.json ) # Keypair of the manager of the stake pool -global_args+=( --staker keys/new_staker.json ) # Keypair of the staker of the stake pool - # Epoch fee, assessed as a percentage of rewards earned by the pool every epoch, # represented as `numerator / denominator` command_args+=( --epoch-fee-numerator 0 ) @@ -30,45 +27,29 @@ command_args+=( --referral-fee 0 ) # Percentage of deposit fee that goes towards command_args+=( --max-validators 3950 ) # Maximum number of validators in the stake pool, 3950 is the current maximum possible -validator_list=validator_list.txt # File containing validator vote account addresses, each will be added to the stake pool after creation - # (Optional) Deposit authority, required to sign all deposits into the pool. # Setting this variable makes the pool "private" or "restricted". -# Comment it out if you want the pool to be open to all depositors. -command_args+=( --deposit-authority keys/authority.json ) +# Uncomment and set to a valid keypair if you want the pool to be restricted. +#command_args+=( --deposit-authority keys/authority.json ) ################################################### ### MODIFY PARAMETERS ABOVE THIS LINE FOR YOUR POOL ################################################### keys_dir=keys -spl_stake_pool=../../../target/debug/spl-stake-pool +spl_stake_pool=spl-stake-pool +# Uncomment to use a local build +#spl_stake_pool=../../../target/debug/spl-stake-pool mkdir -p $keys_dir -build_stake_pool_cli () { - cargo build --manifest-path ../Cargo.toml -} - create_keypair () { - if test ! -f $1 + if test ! -f "$1" then - solana-keygen new --no-passphrase -s -o $1 + solana-keygen new --no-passphrase -s -o "$1" fi } -add_validator_stakes () { - pool=$1 - validator_list=$2 - for validator in $(cat $validator_list) - do - $spl_stake_pool "${global_args[@]}" add-validator $pool $validator - done -} - -echo "Building stake pool CLI" -build_stake_pool_cli - echo "Creating pool" stake_pool_keyfile=$keys_dir/stake-pool.json validator_list_keyfile=$keys_dir/validator-list.json @@ -81,15 +62,9 @@ create_keypair $reserve_keyfile set -ex $spl_stake_pool \ - "${global_args[@]}" \ create-pool \ "${command_args[@]}" \ --pool-keypair "$stake_pool_keyfile" \ --validator-list-keypair "$validator_list_keyfile" \ --mint-keypair "$mint_keyfile" \ --reserve-keypair "$reserve_keyfile" - -stake_pool_pubkey=$(solana-keygen pubkey $stake_pool_keyfile) - -echo "Adding validator stake accounts to the pool" -add_validator_stakes $stake_pool_pubkey $validator_list diff --git a/stake-pool/cli/scripts/setup-test-validator.sh b/stake-pool/cli/scripts/setup-test-validator.sh new file mode 100755 index 00000000000..5fd803dd50b --- /dev/null +++ b/stake-pool/cli/scripts/setup-test-validator.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Script to setup a local solana-test-validator with the stake pool program +# given a maximum number of validators and a file path to store the list of +# test validator vote accounts. + +cd "$(dirname "$0")" || exit +max_validators=$1 +validator_file=$2 + +create_keypair () { + if test ! -f "$1" + then + solana-keygen new --no-passphrase -s -o "$1" + fi +} + +setup_test_validator() { + solana-test-validator -c SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy -c EmiU8AQkB2sswTxVB6aCmsAJftoowZGGDXuytm6X65R3 --url devnet --slots-per-epoch 32 --quiet --reset & + pid=$! + solana config set --url http://127.0.0.1:8899 + solana config set --commitment confirmed + echo "waiting for solana-test-validator, pid: $pid" + sleep 5 +} + +create_vote_accounts () { + max_validators=$1 + validator_file=$2 + for number in $(seq 1 "$max_validators") + do + create_keypair "$keys_dir/identity_$number.json" + create_keypair "$keys_dir/vote_$number.json" + create_keypair "$keys_dir/withdrawer_$number.json" + solana create-vote-account "$keys_dir/vote_$number.json" "$keys_dir/identity_$number.json" "$keys_dir/withdrawer_$number.json" --commission 1 + vote_pubkey=$(solana-keygen pubkey "$keys_dir/vote_$number.json") + echo "$vote_pubkey" >> "$validator_file" + done +} + + +echo "Setup keys directory and clear old validator list file if found" +keys_dir=keys +mkdir -p $keys_dir +if test -f "$validator_file" +then + rm "$validator_file" +fi + +echo "Setting up local test validator" +setup_test_validator + +echo "Creating vote accounts, these accounts be added to the stake pool" +create_vote_accounts "$max_validators" "$validator_file" + +echo "Done adding $max_validators validator vote accounts, their pubkeys can be found in $validator_file" diff --git a/stake-pool/cli/scripts/withdraw.sh b/stake-pool/cli/scripts/withdraw.sh new file mode 100755 index 00000000000..deeee7a0c5f --- /dev/null +++ b/stake-pool/cli/scripts/withdraw.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +# Script to withdraw stakes and SOL from a stake pool, given the stake pool public key +# and a path to a file containing a list of validator vote accounts + +cd "$(dirname "$0")" || exit +stake_pool_keyfile=$1 +validator_list=$2 +withdraw_sol_amount=$3 + +create_keypair () { + if test ! -f "$1" + then + solana-keygen new --no-passphrase -s -o "$1" + fi +} + +withdraw_stakes () { + stake_pool_pubkey=$1 + validator_list=$2 + pool_amount=$3 + while read -r validator + do + $spl_stake_pool withdraw-stake "$stake_pool_pubkey" "$pool_amount" --vote-account "$validator" + done < "$validator_list" +} + +stake_pool_pubkey=$(solana-keygen pubkey "$stake_pool_keyfile") +keys_dir=keys + +spl_stake_pool=spl-stake-pool +# Uncomment to use a locally build CLI +#spl_stake_pool=../../../target/debug/spl-stake-pool + +echo "Setting up keys directory $keys_dir" +mkdir -p $keys_dir +authority=$keys_dir/authority.json +echo "Setting up authority for withdrawn stake accounts at $authority" +create_keypair $authority + +echo "Withdrawing stakes from stake pool" +withdraw_stakes "$stake_pool_pubkey" "$validator_list" "$withdraw_sol_amount" +echo "Withdrawing SOL from stake pool to authority" +$spl_stake_pool withdraw-sol "$stake_pool_pubkey" $authority "$withdraw_sol_amount"