Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit b80c10f

Browse files
authored
stake-pool: Add withdraw-sol command + CLI + docs (#2475)
* stake-pool: plumb sol withdraw fee and authority * Add sol withdraw instruction and processor * Cleanup sysvar usage * Fix stack size violation * Add tests * Add CLI support * Add docs for new command * Integrate review feedback
1 parent 28adc96 commit b80c10f

24 files changed

+1642
-707
lines changed

docs/src/stake-pool.md

Lines changed: 104 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ This document is intended for the main actors of the stake pool system:
3131
* user: provides staked SOL into an existing stake pool
3232

3333
In its current iteration, the stake pool accepts active stakes or SOL, so
34-
deposits may come from either an active stake or SOL wallet. Withdrawals, on the
35-
other hand, only return a fully active stake account, except in certain exceptions.
34+
deposits may come from either an active stake or SOL wallet. Withdrawals
35+
can return a fully active stake account from one of the stake pool's accounts,
36+
or SOL from the reserve.
3637

3738
This means that stake pool managers and stakers must be comfortable with
3839
creating and delegating stakes, which are more advanced operations than sending and
@@ -74,15 +75,23 @@ In exchange for their deposit (SOL or stake), the user receives SPL tokens
7475
representing their fractional ownership in pool. A percentage of the rewards
7576
earned by the pool goes to the pool manager as an epoch fee.
7677

77-
Over time, as the stakes in the stake pool accrue staking rewards, the user's fractional
78-
ownership will be worth more than their initial deposit. Whenever the user chooses,
79-
they can use the `withdraw-stake` instruction to withdraw an activated stake account
80-
in exchange for their SPL pool tokens. The user will get back a SOL stake account
81-
immediately.
78+
Over time, as the stakes in the pool accrue rewards, the user's fractional
79+
ownership will be worth more than their initial deposit.
8280

83-
Note: if the user wants to withdraw the SOL in the stake account, they must first
84-
deactivate the stake account and wait until the next epoch boundary (maximum 2 days).
85-
Once the stake is inactive, they can freely withdraw the SOL.
81+
Whenever they wish to exit the pool, the user may use the `withdraw-sol` instruction
82+
to receive SOL from the stake pool's reserve in exchange for stake pool tokens.
83+
Note that this operation will fail if there is not enough SOL in the stake pool's
84+
reserve, which is normal if the stake pool manager stakes all of the SOL in the pool.
85+
86+
Alternatively, they can use the `withdraw-stake` instruction to withdraw an
87+
activated stake account in exchange for their SPL pool tokens. The user will get
88+
back a SOL stake account immediately. The ability to withdraw stake is always
89+
possible, under all circumstances.
90+
91+
Note: when withdrawing stake, if the user wants to withdraw the SOL in the stake
92+
account, they must first deactivate the stake account and wait until the next
93+
epoch boundary (maximum 2 days). Once the stake is inactive, they can freely
94+
withdraw the SOL.
8695

8796
The stake pool staker can add and remove validators, or rebalance the pool by
8897
decreasing the stake on a validator, waiting an epoch to move it into the stake
@@ -96,37 +105,47 @@ is recovered when removing the validator.
96105
### Fees
97106

98107
The stake pool program provides managers many options for making the pool
99-
financially viable, predominantly through fees. There are four different sources
108+
financially viable, predominantly through fees. There are five different sources
100109
of fees:
101110

102111
* Epoch: every epoch (roughly 2 days), the stake accounts in the pool earn
103112
inflation rewards, so the stake pool mints pool tokens into the manager's fee
104113
account as a proportion of the earned rewards. For example, if the pool earns
105114
10 SOL in rewards, and the fee is set to 2%, the manager will earn pool tokens
106115
worth 0.2 SOL.
107-
* Withdraw: sends a proportion of the desired withdrawal amount to the manager.
116+
* SOL withdraw: sends a proportion of the desired withdrawal amount to the manager
108117
For example, if a user wishes to withdraw 100 pool tokens, and the fee is set
109118
to 3%, 3 pool tokens go to the manager, and the remaining 97 tokens go to the
110-
user in the form of a SOL stake account.
119+
user in the form of a SOL.
120+
* Stake withdraw: sends a proportion of the desired withdrawal amount to the manager
121+
before creating a new stake for the user.
111122
* SOL deposit: converts the entire SOL deposit into pool tokens, then sends a
112123
proportion of those to the manager, and the rest to the user
113124
* Stake deposit: converts the stake account's delegation plus rent-exemption
114125
to pool tokens, sends a proportion of those to the manager, and the rest to
115126
the user
116-
* Referral: during SOL or stake deposits, the pool manager has the option to
117-
redistribute a percentage of the fees to another address as a referral fee.
118-
This option is particularly attractive for wallet providers. When a wallet
119-
integrates a stake pool, the wallet developer will have the option to earn
120-
additional tokens anytime a user deposits into the stake pool. Stake pool
121-
managers can use this feature to create strategic partnerships and entice
122-
greater adoption of stake pools!
123127

124-
### Deposit restrictions
128+
For partner applications, there's the option of a referral fee on deposits.
129+
During SOL or stake deposits, the stake pool can redistribute a percentage of
130+
the fees to another address as a referral fee.
131+
132+
This option is particularly attractive for wallet providers. When a wallet
133+
integrates a stake pool, the wallet developer will have the option to earn
134+
additional tokens anytime a user deposits into the stake pool. Stake pool
135+
managers can use this feature to create strategic partnerships and entice
136+
greater adoption of stake pools!
137+
138+
### Funding restrictions
125139

126140
To give the manager more control over funds entering the pool, stake pools allow
127-
deposit restrictions on SOL and stakes through a SOL deposit authority
128-
and a stake deposit authority. If the field is set, that authority must sign the
129-
associated deposit instruction.
141+
deposit and withdrawal restrictions on SOL and stakes through three different
142+
"funding authorities":
143+
144+
* SOL deposit
145+
* Stake deposit
146+
* SOL withdrawal
147+
148+
If the field is set, that authority must sign the associated instruction.
130149

131150
For example, if the manager sets a stake deposit authority, then that address
132151
must sign every stake deposit instruction.
@@ -140,7 +159,7 @@ This can also be useful in a few situations:
140159
* Maintenance mode. If the pool needs time to reset fees or otherwise, the
141160
manager can temporarily restrict new deposits by setting deposit authorities.
142161

143-
Note: in order to keep user funds safe, withdrawals are always permitted.
162+
Note: in order to keep user funds safe, stake withdrawals are always permitted.
144163

145164
## Background
146165

@@ -301,8 +320,8 @@ the stake pool program currently enforces a limit of 1.5x increase per epoch.
301320
For example, if the current withdrawal fee is 2.5%, the maximum that can be set
302321
for the next epoch is 3.75%.
303322

304-
The possible options for the fee type are `epoch`, `withdrawal`, `sol-deposit`,
305-
and `stake-deposit`.
323+
The possible options for the fee type are `epoch`, `sol-withdrawal`,
324+
`stake-withdrawal`, `sol-deposit`, and `stake-deposit`.
306325

307326
### Set referral fee
308327

@@ -339,6 +358,39 @@ stake pool staker cannot steal funds from the stake pool.
339358
Note: to avoid "disturbing the manager", the staker can also reassign their stake
340359
authority.
341360

361+
### Set Funding Authority
362+
363+
To restrict who can interact with the pool, the stake pool manager may require
364+
a particular signature on stake deposits, SOL deposits, or SOL withdrawals. This
365+
does not make the pool private, since all information is available on-chain, but
366+
it restricts who can use the pool.
367+
368+
As an example, let's say a pool wants to restrict all SOL withdrawals.
369+
370+
```console
371+
$ spl-stake-pool set-funding-authority Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR sol-withdraw AZ1PgxWSxw4ezX8gvpNgGsr39jJHCwtkaXr1mNMwWWeK
372+
Signature: 3gx7ckGNSL7gUUyxh4CU3RH3Lyt88hiCvYQ4QRKtnmrZHvAS93ebP6bf39WYGTeKDMVSJUuwBEmk9VFSaWtXsHVV
373+
```
374+
375+
After running this command, `AZ1PgxWSxw4ezX8gvpNgGsr39jJHCwtkaXr1mNMwWWeK` must
376+
sign all SOL withdrawals, otherwise the operation fails.
377+
378+
After some time, if the manager wishes to enable SOL withdrawals, they can remove
379+
the restriction:
380+
381+
```console
382+
$ spl-stake-pool set-funding-authority Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR sol-withdraw --unset
383+
Signature: 5kWeBqoxyvANMHCP4ydsZRf8QU4hMotLnKkFbTEdvqEVywo4F3MpZtay7D57FbjJZpdp72fc3vrbxJi9qDLfLCnD
384+
```
385+
386+
Now, anyone can withdraw SOL from the stake pool, provided there is enough SOL left
387+
in the reserve.
388+
389+
The options for funding authorities are `sol-withdraw`, `sol-deposit`, and `stake-deposit`.
390+
391+
Note: it is impossible to restrict stake withdrawals. This would create an opportunity
392+
for malicious pool managers to effectively lock user funds.
393+
342394
## Stake Pool Staker Examples
343395

344396
### Add a validator to the pool
@@ -676,6 +728,31 @@ $ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB
676728
100.00000000
677729
```
678730

731+
### Withdraw SOL
732+
733+
Stake pools allow SOL withdrawals directly from the reserve and into a normal
734+
SOL wallet account, and in exchange burns the provided pool tokens.
735+
736+
```console
737+
$ spl-stake-pool withdraw-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 2
738+
Signature: 4bqZKUUrjVspqTGqGqX4zxnHnJB67WbeukKUZRmxJ2yFmr275CtHPjZNzQJD9Pe7Q6mSxnUpcVv9FUdAbGP9RyBc
739+
```
740+
741+
The stake pool burned 2 pool tokens. In return, the stake pool sent SOL to the
742+
fee payer for the transaction. You can check that the pool tokens have been burned:
743+
744+
```console
745+
$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB
746+
98.00000000
747+
```
748+
749+
And you can check that the fee payer has been credited:
750+
751+
```console
752+
$ solana balance
753+
49.660334743 SOL
754+
```
755+
679756
### Deposit stake
680757

681758
Stake pools also accept deposits from active stake accounts, so we must first

stake-pool/cli/scripts/deposit-withdraw.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,5 @@ echo "Depositing stakes into stake pool"
7272
deposit_stakes $stake_pool_pubkey $validator_list
7373
echo "Withdrawing stakes from stake pool"
7474
withdraw_stakes $stake_pool_pubkey $validator_list $half_sol_amount
75+
echo "Withdrawing sol from stake pool"
76+
$spl_stake_pool withdraw-sol $stake_pool_pubkey $half_sol_amount

stake-pool/cli/scripts/setup-stake-pool.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ setup_pool () {
3030
create_keypair $stake_pool_keyfile
3131
create_keypair $mint_keyfile
3232

33-
$spl_stake_pool create-pool --fee-numerator 3 --fee-denominator 100 \
33+
$spl_stake_pool create-pool --epoch-fee-numerator 3 --epoch-fee-denominator 100 \
3434
--withdrawal-fee-numerator 5 --withdrawal-fee-denominator 1000 \
3535
--max-validators $max_validators \
3636
--pool-keypair $stake_pool_keyfile \

0 commit comments

Comments
 (0)