@star-factory/sdk-staking
v0.2.0
Published
Staking SDK for the Star protocol
Readme
sdk-staking
Typed client for the on-chain staking program. It mirrors PDA seeds and instruction accounts, and adds read and convenience helpers.
- Entry:
sdk-staking/index.ts - Types:
sdk-staking/types.ts - Peer deps:
@coral-xyz/anchor,@solana/spl-token
Install
yarn add @coral-xyz/anchor @solana/spl-tokenQuick start
import { AnchorProvider, BN } from '@coral-xyz/anchor';
import { PublicKey } from '@solana/web3.js';
import { StakingSDK } from '.';
const provider = AnchorProvider.env();
const sdk = await StakingSDK.create(provider); // or pass custom programId
// Initialize pool (authority must sign)
await sdk.initialize(new PublicKey('...accepted_mint...'));
// Stake
await sdk.stake(new BN(1_000_000));
// Unstake (starts 30-day unlock)
await sdk.unstake(new BN(500_000));
// Claim when eligible
if (await sdk.canClaimUnstake()) {
await sdk.claimUnstake();
}API
class StakingSDK {
constructor(program: Program<StakeProgram>, provider: AnchorProvider);
static create(provider: AnchorProvider, programId?: PublicKey): Promise<StakingSDK>;
// PDAs
getStakePoolPDA(): PDAWithBump; // [b"stake_pool"]
getUserStakePDA(user: Address): PDAWithBump; // [b"user_stake", user]
getStakeVaultPDA(stakePool: Address): PDAWithBump; // [b"stake_vault", stake_pool]
// Writes
initialize(acceptedMint: Address, authority?: Address): Promise<TransactionSignature>;
stake(amount: Amount, user?: Address): Promise<TransactionSignature>;
unstake(amount: Amount, user?: Address): Promise<TransactionSignature>;
claimUnstake(user?: Address): Promise<TransactionSignature>;
// Reads
getStakePool(): Promise<StakePoolAccount>;
getUserStake(user?: Address): Promise<UserStakeAccount | null>;
// Derived helpers
getUserPoolShare(user?: Address): Promise<number>; // percentage 0..100
canClaimUnstake(user?: Address): Promise<boolean>;
getTimeUntilClaim(user?: Address): Promise<number | null>; // seconds
// Events
onStakeEvent(cb: EventCallback<StakeEvent>): ListenerId;
onUnstakeEvent(cb: EventCallback<UnstakeEvent>): ListenerId;
onClaimUnstakeEvent(cb: EventCallback<ClaimUnstakeEvent>): ListenerId;
removeEventListener(listenerId: ListenerId): Promise<void>;
}Types (subset)
type Address = web3.PublicKey;
type Amount = BN;
interface StakePoolAccount { acceptedMint: Address; totalStaked: BN }
interface UserStakeAccount { stakedAmount: BN; pendingUnstake: BN; unlockTimestamp: BN }Behavior notes
- Loads IDL from
../target/idl/stake_program.json; useStakingSDK.create(provider, programId)to override address. - Uses
.accountsPartial(...)(Anchor v0.29+). If needed, switch to.accounts(...). getUserStake()returnsnullif the PDA is not initialized.getUserPoolShare()computes(stakedAmount / totalStaked) * 100with two-decimal precision.
Staker Snapshot Script
Creates a snapshot of all stakers for pro-rata reward distribution. Outputs CSV compatible with the airdrop script.
Usage
# From sdk-staking directory
yarn snapshot --supply <AMOUNT> [options]
# Options:
# --supply <amount> Total reward tokens to distribute (whole tokens)
# --decimals <n> Reward token decimals (default: 6 for USDC)
# --output <path> Output CSV path (default: ./staker-snapshot.csv)
# --rpc <url> RPC endpoint (default: $RPC_URL or localhost)Examples
# Distribute 1M USDC (6 decimals) to stakers
yarn snapshot --supply 1000000 --decimals 6 --output ./usdc-rewards.csv
# Distribute 500K tokens with 9 decimals on mainnet
yarn snapshot --supply 500000 --decimals 9 --rpc https://api.mainnet-beta.solana.comOutput
Creates three files:
staker-snapshot.csv-wallet,amountformat for airdrop scriptstaker-snapshot-detailed.csv- Full allocation details (staked amounts, percentages)staker-snapshot-summary.json- Verification data and audit trail
Features
- 100% integer arithmetic - No floating point for token amounts
- Verified math -
sum(distributed) + remainder = total_supply - Deterministic ordering - Sorted by wallet address for reproducibility
- Randomized output - CSV is shuffled so whales aren't airdropped first
Programmatic Usage
import { StakingSDK } from '@star-vault/sdk-staking';
const sdk = await StakingSDK.create(provider);
// Get all stakers
const { stakers, totalStaked, activeStakers } = await sdk.getAllStakers();
// Each staker has:
// - wallet: PublicKey
// - stakedAmount: BN
// - pendingUnstake: BN
// - unlockTimestamp: BN