Skip to main content

Single-Validator Stake Pool

Trustless liquid staking for all Solana validators.

InformationAccount Address
Single Pool ProgramSVSPxpvHdN29nkVg9rPapPNDddN5DipNLRUFhyjFThE

Overview

The single-validator stake pool program is an SPL program that enables liquid staking with zero fees, no counterparty, and 100% capital efficiency.

The program defines a canonical pool for every vote account, which can be initialized permissionlessly, and mints tokens in exchange for stake delegated to its designated validator.

The program is a stripped-down adaptation of the existing multi-validator stake pool program, with approximately 80% less code, to minimize execution risk.

Source

The Single Pool Program's source is available on GitHub.

Security Audits

The Single Pool Program has received three audits to ensure total safety of funds:

Interface

The single-validator stake pool program is written in Rust and available on crates.io and docs.rs.

Javascript bindings are available for Web3.js Classic and Web3.js Next.

Reference Guide

Environment Setup

The easiest way to interact with the single pool program is using the spl-single-pool command-line program. With Rust installed, run:

$ cargo install spl-single-pool-cli

Run spl-single-pool --help for a full description of available commands.

Configuration

The spl-single-pool configuration is shared with the solana command-line tool.

Current Configuration

$ 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
Commitment: confirmed

Cluster RPC URL

See Solana clusters for cluster-specific RPC URLs

$ solana config set --url https://api.devnet.solana.com

Default Keypair

See Keypair conventions for information on how to setup a keypair if you don't already have one.

Keypair File

$ solana config set --keypair ${HOME}/new-keypair.json

Hardware Wallet URL (See URL spec)

$ solana config set --keypair usb://ledger/

spl-single-pool generally uses the default keypair as the fee-payer, the wallet to draw funds from (for instance, to fund new stake accounts), and the signing authority on accounts that require one. When token accounts are required, it defaults to the default keypair's associated account. All of these roles can be overridden by command-line flags.

Setting up a single-validator pool

Creating the pool

A single-validator stake pool can be created permissionlessly, by anyone, for a given vote account. This allows you to receive the full staking yield you would by staking directly while holding the value in a tokenized form. It also allows you to buy or sell stakes smaller than the minimum delegation on the market.

Assuming a vote account Ammgaa2iZfA745BmZMhkcS27uh87fEVDC6Gm2RXz5hrC exists, we create a pool at address DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb:

$ spl-single-pool manage initialize Ammgaa2iZfA745BmZMhkcS27uh87fEVDC6Gm2RXz5hrC

Managing token metadata

By default, when a pool is created, it also creates Metaplex token metadata for the mint associated with the pool. If, for whatever reason, this was opted out of by the pool creator, anyone may create the default metadata permissionlessly:

$ spl-single-pool manage create-token-metadata --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb

The default token metadata is only minimally helpful, spotlighting the address of the validator vote account. The owner of the vote account, however, can change the metadata to anything they wish. They prove their identity by signing with the vote account's authorized withdrawer; this is the only permissioned instruction on the pool.

$ spl-single-pool manage update-token-metadata DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb "My Cool Pool" cPool "https://www.cool.pool/token.jpg"

The URL parameter is optional.

Using a single-validator pool

Depositing

When a pool is created, its stake account is delegated to the appropriate vote account, and for that epoch, stake in an "activating" state can be deposited into it. After this epoch, stake must be in an "active" state to deposit into the pool. That is, it must be delegated to the vote account, and a deposit can only be performed after the next epoch boundary.

Assuming the stake account 9cc4cmLcZA89fYmcVPPTLmHPQ5gab3R6jMqj124abkSi is in an active state:

$ spl-single-pool deposit 9cc4cmLcZA89fYmcVPPTLmHPQ5gab3R6jMqj124abkSi

When an explicit stake account address is provided, the CLI can determine the pool address automatically.

All versions of the deposit command/transaction automatically create the associated token account for the pool token if it doesn't exist and no auxiliary token account address is provided.

The program also makes available a convenience address for each pool, called the default deposit address. This allows a flow where you create and delegate a stake at a program-derived address, and then can deposit this stake after the epoch boundary, without having to generate or keep track of any new keypairs. The user retains full authority on the stake account until they decide to deposit.

$ spl-single-pool create-default-stake --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb 1000000000

Once the stake becomes active, typically in the next epoch:

$ spl-single-pool deposit --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb --default-stake-account

Withdrawing

Withdrawing is simple, burning tokens to receive the amount of stake they're backed by. Stake can be withdrawn into an active stake account delegated to the appropriate vote account, or to a new stake account, with all authority assigned to the user wallet. Internally, all versions of the withdraw command/transaction use a token delegate to accomplish the burn. This means the user does not have to provide a wallet signature to the single pool program.

$ spl-single-pool withdraw --pool DkE6XFGbqSyYzRugLVSmmB42F9BQZ7mZU837e2Cti7kb 1000000000

The --deactivate flag may also be passed, as a convenience to start the undelegation process.