An on-chain staking contract built on Solana using the Anchor framework. Users deposit SPL tokens into program-controlled vaults, earn yield over time, and face early withdrawal penalties to incentivize long-term participation.
- Token staking — deposit SPL tokens into a PDA-controlled vault
- Yield accrual — rewards calculated based on staked amount and duration
- Lock-up periods — configurable lock duration per stake entry
- Early withdrawal penalties — penalty applied to withdrawals before lock-up expires
- CPI integration — uses Cross-Program Invocation to interact with the SPL Token program
- PDA-based accounts — stake entries derived from user public keys for trustless custody
User Wallet
│
▼
[stake instruction]
│
├──► StakeEntry PDA (seeds: ["stake_entry", user])
│ stores: amount, timestamp, lock_period
│
└──► Vault TokenAccount (PDA-controlled)
holds: staked SPL tokens
| Account | Type | Description |
|---|---|---|
StakeEntry |
PDA | Per-user stake record storing amount and lock metadata |
user_token_account |
TokenAccount | User's SPL token account (source) |
vault |
TokenAccount | Program-controlled token vault (destination) |
| Tool | Version |
|---|---|
| Anchor | 0.31.1 |
| Solana platform-tools | v1.52 |
| Rust | 1.89.0-sbpf |
| SPL Token | 7.0.0 |
- Rust
- Solana CLI
- Anchor CLI
0.31.1 - Node.js
>= 18
git clone https://github.com/YOUR_USERNAME/spl-staking.git
cd spl-staking
yarn install# Make sure rustup's cargo shim is first in PATH
export PATH="$HOME/.cargo/bin:$PATH"
anchor build# Terminal 1 — start local validator
solana-test-validator
# Terminal 2 — configure CLI and deploy
solana config set --url localhost
solana airdrop 10
anchor deployanchor test --skip-local-validatorStake entries are stored in PDAs derived from the user's public key, meaning each user has a deterministic on-chain account that only this program can sign for:
seeds = [b"stake_entry", user.key().as_ref()],
bump,Token transfers use CPI calls into the SPL Token program, allowing the staking contract to move tokens on behalf of users without holding private keys:
token::transfer(cpi_ctx, amount)?;Early withdrawals before the lock period expires incur a configurable penalty, which is either burned or redirected to a rewards pool.
spl-staking/
├── programs/
│ └── spl-staking/
│ └── src/
│ └── lib.rs # Program entrypoint and instructions
├── tests/
│ └── spl-staking.ts # Integration tests
├── Anchor.toml # Anchor workspace config
├── Cargo.toml # Workspace manifest
└── package.json
| Network | Address |
|---|---|
| Localnet | E4ujhyaQNbyw7epzKuSwEDVP6GmpLanYuPmPaahL3eSn |
MIT