0.6.5 • Published 5 months ago

@tomb-labs/staking v0.6.5

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

Tomb Labs Staking SDK

A TypeScript SDK for interacting with the Tomb Labs Staking Program on Solana. This SDK provides a comprehensive interface for managing NFT staking operations, including support for both standard and programmable NFTs.

Features

  • Full TypeScript support with comprehensive type definitions
  • Easy-to-use methods for all program instructions
  • Support for both standard and programmable NFTs
  • Built-in validation and error handling
  • Utility functions for PDA derivation
  • Built-in account type definitions
  • Efficient account data fetching utilities
  • React hooks support
  • Transaction building mode for custom signing
  • Compatible with any wallet adapter

Installation

npm install @tomb-labs/staking-sdk

Quick Start

Using with a Custom Wallet

import { StakingClient } from '@tomb-labs/staking-sdk';
import { Connection, PublicKey, Transaction } from '@solana/web3.js';

// Your wallet must implement this interface
interface WalletAdapter {
  publicKey: PublicKey | null;
  signTransaction: <T extends Transaction>(tx: T) => Promise<T>;
  signAllTransactions: <T extends Transaction>(txs: T[]) => Promise<T[]>;
}

// Initialize connection and wallet
const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet: WalletAdapter = {
  // Your wallet implementation
};

// Create SDK client
const client = new StakingClient(connection, wallet);

Using with Solana Wallet Adapter

import { StakingClient } from '@tomb-labs/staking-sdk';
import { useConnection, useWallet } from '@solana/wallet-adapter-react';

// In your React component
const { connection } = useConnection();
const wallet = useWallet();

// Create SDK client - wallet-adapter-react implements the required interface
const client = new StakingClient(connection, wallet);

Using Transaction Builder Mode

import { StakingClient } from '@tomb-labs/staking-sdk';
import { Connection, Keypair } from '@solana/web3.js';

// Initialize connection and wallet
const connection = new Connection('https://api.mainnet-beta.solana.com');
const keypair = Keypair.generate();

// Create a simple wallet adapter
const wallet = {
  publicKey: keypair.publicKey,
  signTransaction: async tx => {
    tx.partialSign(keypair);
    return tx;
  },
  signAllTransactions: async txs => {
    return txs.map(tx => {
      tx.partialSign(keypair);
      return tx;
    });
  },
};

// Create SDK client
const client = new StakingClient(connection, wallet);

// Build transaction without signing
const tx = await client.projects.createProject({
  name: 'my-project',
  authority: wallet.publicKey,
  image_url: 'https://example.com/image.png',
  fees: {
    stakeFee: 1000000,
    unstakeFee: 1000000,
    claimFee: 1000000,
  },
  buildOnly: true, // This flag makes the method return a Transaction instead of sending it
});

// Now you can sign and send the transaction however you want
const signature = await wallet.signTransaction(tx);
const txid = await connection.sendRawTransaction(signature.serialize());

Usage Examples

Creating a Project

try {
  // Direct signing mode (default)
  const signature = await client.projects.createProject({
    name: 'my-project',
    authority: wallet.publicKey,
    image_url: 'https://example.com/image.png',
    fees: {
      stakeFee: 1000000,
      unstakeFee: 1000000,
      claimFee: 1000000,
    },
  });

  // OR using transaction builder mode
  const tx = await client.projects.createProject({
    name: 'my-project',
    authority: wallet.publicKey,
    image_url: 'https://example.com/image.png',
    fees: {
      stakeFee: 1000000,
      unstakeFee: 1000000,
      claimFee: 1000000,
    },
    buildOnly: true,
  });

  // Sign and send the transaction yourself
  const signature = await wallet.sendTransaction(tx, connection);

  console.log('Project created:', signature);
} catch (error) {
  if (error instanceof StakingError) {
    console.error('Staking error:', error.message);
  } else {
    console.error('Unexpected error:', error);
  }
}

Creating a Staking Pool

try {
  const tx = await client.createPool({
    name: 'my-nft-pool',
    maxStakers: 1000,
    collectionKey: collectionPublicKey, // Optional: NFT collection address
    requiresAuthorization: false,
    rewardMint: rewardTokenMintPublicKey,
    authority: wallet.publicKey,
  });

  console.log('Pool created:', tx);
} catch (error) {
  if (error instanceof StakingError) {
    console.error('Staking error:', error.message);
  } else {
    console.error('Unexpected error:', error);
  }
}

Staking an NFT

try {
  // For standard NFTs
  const tx = await client.stakeStandard({
    name: 'my-nft-pool',
    authority: wallet.publicKey,
    projectAuthority: projectAuthorityPublicKey,
    rewardMint: rewardMintPublicKey,
    nftMint: nftMintPublicKey,
  });

  console.log('NFT staked:', tx);
} catch (error) {
  if (error instanceof StakingError) {
    // Handle specific staking errors
    switch (error.message) {
      case ERRORS.POOL_INACTIVE:
        console.error('Pool is not active');
        break;
      case ERRORS.INVALID_COLLECTION:
        console.error('NFT is not from the required collection');
        break;
      default:
        console.error('Staking error:', error.message);
    }
  } else {
    console.error('Unexpected error:', error);
  }
}

Claiming Rewards

try {
  const tx = await client.claimReward({
    name: 'my-nft-pool',
    authority: wallet.publicKey,
    projectAuthority: projectAuthorityPublicKey,
    rewardMint: rewardMintPublicKey,
  });

  console.log('Rewards claimed:', tx);
} catch (error) {
  if (error instanceof StakingError) {
    if (error.message === ERRORS.NO_REWARDS) {
      console.log('No rewards available to claim');
    } else {
      console.error('Claim error:', error.message);
    }
  }
}

Fetching Account Data

The SDK provides a dedicated Fetcher class for efficient account data retrieval. You can access it through the client's fetcher property:

// Access the fetcher
const fetcher = client.fetcher;

// Get global state and fees
const globalState = await fetcher.getGlobalState();
const fees = await fetcher.getGlobalFees();

// Get project information
const project = await fetcher.getProjectState({
  authority: authorityPublicKey, // or pda: projectPDA
});
const allProjects = await fetcher.getAllProjects();

// Get pool information
const pool = await fetcher.getPoolState({
  pda: poolPublicKey, // or
  authority: authorityPublicKey,
  name: 'pool-name',
  rewardMint: rewardMintPublicKey,
});

// Get pools for a project
const projectPools = await fetcher.getAllPoolsForProject({
  authority: projectAuthorityPublicKey, // or pda: projectPDA
});

// Get pools for a staker
const stakerPools = await fetcher.getAllPoolsForStaker({
  authority: stakerPublicKey, // or pda: stakerPDA
});

// Get all pools
const allPools = await fetcher.getAllPools();

// Get staker information
const staker = await fetcher.getStakerState({
  pda: stakerPDA, // or
  authority: stakerPublicKey,
  pool: poolPublicKey,
});

// Get stakers for a pool
const poolStakers = await fetcher.getAllStakersForPool({
  pda: poolPublicKey, // or
  authority: poolAuthorityPublicKey,
  name: 'pool-name',
  rewardMint: rewardMintPublicKey,
});

// Get all stakers
const allStakers = await fetcher.getAllStakers();

// Get staked item information
const stakedItem = await fetcher.getStakedItemState({
  pda: stakedItemPDA, // or
  pool: poolPublicKey,
  nftMint: nftMintPublicKey,
});

// Get staked items for a staker
const stakerItems = await fetcher.getAllStakedItemsForStaker({
  pda: stakerPDA, // or
  authority: stakerPublicKey,
  pool: poolPublicKey,
});

// Get staked items for a pool
const poolItems = await fetcher.getAllStakedItemsForPool({
  pda: poolPublicKey, // or
  authority: poolAuthorityPublicKey,
  name: 'pool-name',
  rewardMint: rewardMintPublicKey,
});

// Get staked items for a project
const projectItems = await fetcher.getAllStakedItemsForProject({
  pda: projectPDA, // or
  authority: projectAuthorityPublicKey,
});

// Get all staked items
const allItems = await fetcher.getAllStakedItems();

// Get all stakers for a project
const projectStakers = await fetcher.getAllStakersForProject({
  pda: projectPDA, // or
  authority: projectAuthorityPublicKey,
});

Each fetch method supports either direct PDA lookup or deriving PDAs from provided parameters. The methods are designed to be flexible while maintaining type safety and proper error handling.

Error Handling

All fetcher methods include comprehensive error handling:

try {
  const project = await fetcher.getProjectState({
    authority: authorityPublicKey,
  });
} catch (error) {
  if (error instanceof StakingError) {
    // Handle specific staking errors
    console.error('Staking error:', error.message);
  } else {
    // Handle unexpected errors
    console.error('Unexpected error:', error);
  }
}

Return Types

Most fetcher methods return objects containing both the account data and the account's public key:

interface FetchResult<T> {
  publicKey: PublicKey;
  account: T;
}

// Example usage
const pools = await fetcher.getAllPoolsForProject({
  authority: projectAuthority,
});
pools.forEach(({ publicKey, account }) => {
  console.log('Pool:', publicKey.toBase58());
  console.log('Status:', account.status);
  console.log('Stakers:', account.stakers);
});

Error Handling

The SDK provides a custom StakingError class and predefined error messages:

import { StakingError, ERRORS } from '@tomb-labs/staking-sdk';

try {
  // SDK operation
} catch (error) {
  if (error instanceof StakingError) {
    switch (error.message) {
      case ERRORS.POOL_INACTIVE:
      case ERRORS.MAX_STAKERS_REACHED:
      case ERRORS.INVALID_STAKER:
      case ERRORS.INVALID_NFT_MINT:
      case ERRORS.INVALID_COLLECTION:
      case ERRORS.UNAUTHORIZED:
      case ERRORS.ALREADY_STAKED:
      case ERRORS.NOT_STAKED:
      case ERRORS.NO_REWARDS:
      case ERRORS.INSUFFICIENT_FUNDS:
        // Handle specific error cases
        break;
      default:
      // Handle unknown staking error
    }
  }
}

API Reference

StakingClient

The main client class for interacting with the staking program.

Constructor

constructor(
  connection: Connection,
  wallet: Wallet,
  opts?: ConfirmOptions
)

Properties

  • fetcher: Fetcher - Instance of the Fetcher class for account data retrieval

Methods

Staking Operations
  • stakeStandard(params: StakeStandardParams): Promise<string>
  • stakeProgrammable(params: StakeProgrammableParams): Promise<string>
  • unstakeStandard(params: UnstakeStandardParams): Promise<string>
  • unstakeProgrammable(params: UnstakeProgrammableParams): Promise<string>
  • claimReward(params: ClaimRewardParams): Promise<string>
Pool Management
  • createPool(params: CreatePoolParams): Promise<string>
  • initStaker(params: InitStakerParams): Promise<string>

Fetcher

A utility class for fetching and querying account data.

Methods

Global State
  • getGlobalState(): Promise<GlobalState> - Fetch global program state
  • getGlobalFees(): Promise<GlobalFees> - Fetch global fee configuration
Projects
  • getProjectState(projectPubkey: PublicKey): Promise<Project> - Fetch a specific project
  • getAllProjects(): Promise<Project[]> - Fetch all projects
Pools
  • getPoolState(poolPubkey: PublicKey): Promise<StakingPool> - Fetch a specific pool
  • getAllPoolsForProject(projectPubkey: PublicKey): Promise<StakingPool[]> - Fetch all pools for a project
  • getAllPoolsForStaker(stakerPubkey: PublicKey): Promise<StakingPool[]> - Fetch all pools a staker participates in
  • getAllPools(): Promise<StakingPool[]> - Fetch all staking pools
Stakers
  • getStakerState(stakerPubkey: PublicKey): Promise<Staker> - Fetch a specific staker
  • getAllStakersForPool(poolPubkey: PublicKey): Promise<Staker[]> - Fetch all stakers in a pool
  • getAllStakers(): Promise<Staker[]> - Fetch all stakers
Staked Items
  • getStakedItemState(nftMint: PublicKey): Promise<StakedItem> - Fetch a specific staked item
  • getAllStakedItemsForStaker(stakerPubkey: PublicKey): Promise<StakedItem[]> - Fetch all items staked by a staker
  • getAllStakedItemsForPool(poolPubkey: PublicKey): Promise<StakedItem[]> - Fetch all items staked in a pool
  • getAllStakedItemsForProject(projectPubkey: PublicKey): Promise<StakedItem[]> - Fetch all items staked in a project
  • getAllStakedItems(): Promise<StakedItem[]> - Fetch all staked items

Utility Functions

The SDK provides utility functions for deriving PDAs:

  • findGlobalStatePDA()
  • findProjectPDA(authority: PublicKey)
  • findStakingPoolPDA(project: PublicKey, rewardMint: PublicKey, name: string)
  • findStakerPDA(stakingPool: PublicKey, authority: PublicKey)
  • findStakedItemPDA(stakingPool: PublicKey, nftMint: PublicKey)

Development

# Install dependencies
npm install

# Build the SDK
npm run build

# Run tests
npm test

# Format code
npm run format

# Lint code
npm run lint

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

Support

For support, please open an issue in the GitHub repository or contact the Tomb Labs team.

Project Management

Projects in the Tomb Labs Staking Program can manage multiple staking pools. Each project has the following key characteristics:

  • Project identification
    • Name: Human-readable project identifier
    • Image URL: Visual representation of the project
  • Pool management
    • Maximum pool limit (maxPools): Each project can manage up to 10 pools
    • Active pool tracking (poolsCount): Current number of active pools
    • Pool storage: Array of pool addresses (fixed size of 10)
  • Fee configuration: Project-specific fees for staking operations
  • Fee wallet: Designated wallet for collecting project fees
// Create a new project
const tx = await client.createProject({
  authority: wallet.publicKey,
  name: 'My Awesome Project',
  image_url: 'https://example.com/project-image.png',
  feeWallet: feeWalletPublicKey, // Optional: defaults to authority
  fees: {
    stakeFee: 0.1, // Optional: fee for staking (in SOL)
    unstakeFee: 0.1, // Optional: fee for unstaking (in SOL)
    claimFee: 0.1, // Optional: fee for claiming rewards (in SOL)
  },
});

// Update project information
await client.updateProjectName({
  authority: wallet.publicKey,
  newName: 'New Project Name',
});

await client.updateProjectImageUrl({
  authority: wallet.publicKey,
  newImageUrl: 'https://example.com/new-image.png',
});

// Get project information
const project = await client.fetcher.getProjectState(projectPublicKey);
console.log('Project name:', project.name);
console.log('Project image:', project.image_url);
console.log('Max pools allowed:', project.maxPools);
console.log('Current active pools:', project.poolsCount);
console.log('Pool addresses:', project.pools);

// Get all pools for a project
const projectPools = await client.fetcher.getAllPoolsForProject(projectPublicKey);
0.6.3

5 months ago

0.6.2

5 months ago

0.6.5

5 months ago

0.6.4

5 months ago

0.5.0

5 months ago

0.6.1

5 months ago

0.6.0

5 months ago

0.4.1

5 months ago

0.4.0

5 months ago

0.3.0

5 months ago

0.2.2

5 months ago

0.2.1

5 months ago

0.2.0

5 months ago

0.1.0

5 months ago

0.0.12

5 months ago

0.0.11

5 months ago

0.0.10

5 months ago

0.0.9

5 months ago

0.0.8

5 months ago

0.0.7

5 months ago

0.0.6

5 months ago

0.0.5

5 months ago

0.0.4

5 months ago

0.0.3

5 months ago

0.0.2

5 months ago

0.0.1

5 months ago