Skip to content

Swarnim-Chandve/nft-staking

Repository files navigation

NFT Staking Program

A Solana smart contract (written in Rust using Anchor) for staking NFTs and earning fungible token rewards. This repository enables users to stake their NFTs (SPL token standard), accrue rewards over time, and claim or unstake them according to configurable parameters. TypeScript-based integration tests are included for simulation and validation.


Table of Contents


Overview

This project enables a staking system for NFTs (Non-Fungible Tokens) on Solana:

  • Users stake their NFTs in a vault and accrue reward tokens over time.
  • Rewards are distributed as fungible SPL tokens minted by the program.
  • Unstaking is subject to a configurable freeze period and max unstake count.
  • Fully decentralized, secure, and extensible for NFT-based reward systems.

Features

  • Configurable Staking Parameters: Admin sets reward rate, freeze period, and max unstake per user.
  • NFT Vault: Staked NFTs are held in secure vault accounts (PDAs).
  • Reward Mint: Fungible tokens minted as staking rewards.
  • Stake/Unstake/Claim: Users can stake NFTs, wait for freeze period, and claim rewards or unstake NFTs.
  • Per-User Accounts: Tracks staking state and rewards for each user.
  • Multiple NFT Support: Users can stake multiple NFTs independently.

Architecture

Smart Contract (Rust/Anchor)

  • Entrypoint: programs/nft-staking/src/lib.rs
  • Instructions:
    • initialize_config: Admin sets up global staking config and creates reward mint.
    • initialize_user: User creates their personal staking account.
    • stake: Stake an NFT (moves NFT to vault, creates stake record).
    • claim_rewards: Mint and distribute reward tokens to user.
    • unstake: Withdraw staked NFT after freeze period.
  • State:
    • Config PDA: Stores staking parameters (reward rate, freeze, max unstake).
    • Reward Mint PDA: Mint for fungible reward tokens, owned by config PDA.
    • Vault PDAs: One per staked NFT, stores NFT while staked.
    • User Account PDA: Tracks user’s staking status and rewards.
    • Stake Record PDA: Tracks each staked NFT by user.

PDAs (Program Derived Addresses)

  • Config: PDA("config")
  • Reward Mint: PDA("rewards", config)
  • Vault: PDA("vault", nft_mint)
  • User Account: PDA("user", user_pubkey)
  • Stake Record: PDA("stake", user_pubkey, nft_mint)

Directory Structure

nft-staking/
├── programs/
│   └── nft-staking/
│       ├── src/
│       │   ├── lib.rs                 # Main entrypoint
│       │   ├── instructions/          # Instruction handlers
│       │   ├── state/                 # Account state definitions
│       │   ├── errors.rs              # Custom error codes
│       │   └── constants.rs
│       └── Cargo.toml
├── tests/
│   └── nft-staking.ts                 # TypeScript integration tests
├── migrations/
│   └── deploy.ts                      # Anchor deployment script
├── Anchor.toml                        # Anchor config
└── README.md                          # This file

Getting Started

Prerequisites

Installation

Clone and install dependencies:

git clone https://github.com/Swarnim-Chandve/nft-staking.git
cd nft-staking
anchor install
npm install

Build the Program

anchor build

Testing

Run localnet tests (Mocha/TypeScript):

anchor test

Test Workflow

  • Setup: Creates admin and user accounts, mints NFTs and reward tokens.
  • Config: Initializes staking config with reward parameters.
  • User: Initializes user account.
  • Staking: Stakes NFTs and verifies vault/account state.
  • Unstaking: Waits for freeze period and unstakes NFTs.
  • Claiming: Claims rewards and verifies token balances.

Test logs show transaction signatures, balances, and on-chain state after each operation.


Deployment

Set cluster and wallet in Anchor.toml as desired.

Deploy to cluster:

anchor deploy

Custom deployment logic can be added in migrations/deploy.ts.


Smart Contract API Reference

Instructions

1. initialize_config(points_per_stake, max_unstake, freeze_period)

  • Admin only. Creates global config and reward mint.
  • Parameters:
    • points_per_stake (u8): Reward tokens per stake.
    • max_unstake (u8): Maximum NFTs a user can unstake at once.
    • freeze_period (u32): Minimum seconds before unstake allowed.
  • Accounts:
    • Admin (Signer)
    • Config PDA
    • Reward Mint PDA

2. initialize_user()

  • Creates a staking user account.
  • Accounts:
    • User (Signer)
    • User Account PDA

3. stake()

  • Stake an NFT, moving it to vault and creating a stake record.
  • Accounts:
    • User (Signer)
    • User Account PDA
    • Config PDA
    • NFT Mint, User NFT ATA, Vault ATA, Stake Record PDA

4. unstake()

  • Unstake NFT after freeze period, returning NFT to user.
  • Accounts:
    • User (Signer)
    • User Account PDA
    • Config PDA
    • NFT Mint, User NFT ATA, Vault ATA, Stake Record PDA

5. claim_rewards()

  • Mint reward tokens to user for staked NFTs.
  • Accounts:
    • User (Signer)
    • User Account PDA
    • Config PDA
    • Reward Mint PDA, User Reward ATA

Security Considerations

  • PDAs: Vaults and mints are owned by PDAs to prevent unauthorized withdrawals/minting.
  • Freeze Period: Prevents instant unstake, reducing reward gaming.
  • Max Unstake: Limits batch unstake to prevent abuse.
  • Checked Transfers: All token operations use SPL checked instructions.
  • Rent Exemption: All accounts created are rent-exempt.

Troubleshooting

  • Insufficient SOL: Use airdrop in localnet for test accounts.
  • Account Already Exists: Anchor handles init_if_needed for PDAs.
  • Unstake Fails: Ensure freeze period has elapsed and you haven't exceeded max unstake.
  • Transaction Fails: Confirm all PDAs and ATAs are correct and funded.

Contributing

  • Fork and submit PRs!
  • Open issues for bugs or features.
  • Please add tests for new logic.

License

MIT License


Acknowledgements


Contact

Open a GitHub issue for questions or support.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published