Skip to content

A Solana program for managing quote-only fee distribution from DAMM v2 LP positions to investors based on locked token amounts from Streamflow vesting schedules.

License

Notifications You must be signed in to change notification settings

1BDO/star-damm-fee-module

Repository files navigation

Star DAMM v2 Fee Module

A Solana program for managing quote-only fee distribution from DAMM v2 LP positions to investors based on locked token amounts from Streamflow vesting schedules.

Overview

This module creates and manages an "honorary" DAMM v2 LP position that accrues fees exclusively in the quote mint. Fees are distributed daily via a permissionless crank to investors pro-rata based on their still-locked tokens, with the remainder going to the creator.

Features

  • Quote-Only Enforcement: Validates and enforces that fees accrue only in quote mint
  • 24-Hour Distribution Window: Permissionless crank callable once per day
  • Pro-Rata Distribution: Distributes based on locked tokens from Streamflow
  • Daily Caps: Optional limits on investor distributions
  • Dust Handling: Minimum payout thresholds to avoid micro-transactions
  • Pagination Support: Handles large investor sets across multiple transactions
  • Pause Mechanism: Emergency pause/unpause functionality
  • Idempotent Retries: Safe to retry failed transactions without double-paying

Installation

Prerequisites

Enter the following command in your terminal to install all the necessary dependencies:

curl --proto '=https' --tlsv1.2 -sSfL https://solana-install.solana.workers.dev | bash

Verify successful installation by checking the version of each installed dependency.

rustc --version && solana --version && anchor --version && node --version && yarn --version

Setup

# Clone repository
git clone https://github.com/1BDO/star-damm-fee-module.git
cd star-damm-fee-module

# Install dependencies
npm install

# Build program
anchor build

# Run tests
anchor test

Documentation

This project includes comprehensive documentation:

Usage

1. Initialize Honorary Position

const positionIndex = 0;
const investorFeeShareBps = 8000; // 80% max to investors
const minPayoutLamports = new BN(1000);
const tickLower = 0;
const tickUpper = 100;

await program.methods
  .initializeHonoraryPosition(
    investorFeeShareBps,
    null, // No daily cap
    minPayoutLamports,
    tickLower,
    tickUpper,
    positionIndex
  )
  .accounts({
    initializer: creator,
    vault: vaultPubkey,
    investorFeePositionOwnerPda: ownerPda,
    honoraryPosition,
    policy,
    pool: poolPubkey,
    quoteMint,
    baseMint,
    programQuoteTreasury,
    // ...
  })
  .rpc();

2. Execute Distribution Crank

const y0 = new BN(1000000); // Total investor allocation at TGE
const isLastPage = true;
const investorStreams = [
  {
    investorPubkey: investor1,
    streamPubkey: stream1,
    investorQuoteAta: ata1,
    y0Allocation: new BN(500000),
  },
  // ... more investors
];

await program.methods
  .crankDistribute(y0, isLastPage, investorStreams)
  .accounts({
    crankCaller: crankerWallet,
    vault: vaultPubkey,
    pool: poolPubkey,
    honoraryPosition,
    ownerPda,
    policy,
    progress,
    programQuoteTreasury,
    creatorQuoteAta,
    // ...
  })
  .remainingAccounts([
    // Streamflow stream accounts
    // Investor ATAs
  ])
  .rpc();

3. Update Policy

await program.methods
  .updatePolicy(
    7500, // New fee share
    { some: new BN(10_000_000) }, // Daily cap
    new BN(5000) // New minimum payout
  )
  .accounts({
    creator,
    policy,
  })
  .rpc();

4. Pause System

// Pause
await program.methods
  .setPauseState(true)
  .accounts({ creator, policy })
  .rpc();

// Unpause
await program.methods
  .setPauseState(false)
  .accounts({ creator, policy })
  .rpc();

Distribution Logic

Fee Calculation

1. Calculate locked fraction:
   f_locked(t) = locked_total(t) / Y0

2. Determine eligible share:
   eligible_share_bps = min(investor_fee_share_bps, floor(f_locked(t) * 10000))

3. Calculate investor fee:
   investor_fee_quote = floor(claimed_quote * eligible_share_bps / 10000)

4. Apply daily cap:
   capped_fee = min(investor_fee_quote, remaining_capacity)

5. Calculate creator share:
   creator_share = claimed_quote - capped_fee

Pro-Rata Distribution

1. For each investor i:
   weight_i(t) = locked_i(t) / locked_total(t)

2. Payout calculation:
   payout_i = floor(investor_fee_quote * weight_i(t))

3. Apply dust threshold:
   if payout_i >= min_payout_lamports:
       distribute payout_i
   else:
       carry_over += payout_i

Event Emissions

PositionInitializedEvent

pub struct PositionInitializedEvent {
    pub pool: Pubkey,
    pub position: Pubkey,
    pub quote_mint: Pubkey,
    pub tick_lower: i32,
    pub tick_upper: i32,
    pub investor_fee_share_bps: u16,
}

DistributionEvent

pub struct DistributionEvent {
    pub day_index: u32,
    pub total_claimed: u64,
    pub investor_share: u64,
    pub creator_share: u64,
    pub investor_count: u32,
    pub pagination_page: u16,
    pub is_final_page: bool,
}

Error Codes

Code Error Description
6000 InvalidPDA Invalid PDA derivation
6001 InvalidInvestorFeeShareBps Invalid investor fee share basis points
6002 InvalidTickRange Invalid tick range or spacing
6003 InvalidPoolConfiguration Pool configuration does not support quote-only fee accrual
6004 BaseFeesDetected Base fees detected - quote-only enforcement failed
6005 DistributionWindowNotElapsed Distribution window not elapsed (24h gate)
6006 InvalidStreamflowData Invalid Streamflow stream data
6007 MathOverflow Mathematical overflow in distribution calculation
6008 InsufficientQuoteFees Insufficient quote fees for distribution
6009 InvalidInvestorStreamInfo Invalid investor stream info
6010 Unauthorized Unauthorized - creator only
6011 SystemPaused System is paused
6012 InvalidPagination Invalid pagination data
6013 DailyCapExceeded Daily cap exceeded
6014 InvalidPositionIndex Invalid position index
6015 QuoteMintValidationFailed Quote mint validation failed
6016 DistributionAlreadyCompleted Distribution already completed for this page

About

A Solana program for managing quote-only fee distribution from DAMM v2 LP positions to investors based on locked token amounts from Streamflow vesting schedules.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published