A Solana-based memecoin launchpad with bonding curve mechanics
DumpFun is a decentralized token launch platform that enables anyone to create and trade memecoins using an automated bonding curve mechanism. Built on Solana using the Anchor framework, it provides fair price discovery and liquidity for newly launched tokens without requiring traditional market makers.
- Overview
- Key Features
- Architecture
- Bonding Curve Mechanics
- Smart Contract Structure
- Instructions
- State Management
- Events
- Security Features
- Fees
- Deployment
- Integration Guide
- Testing
DumpFun implements a bonding curve-based token launch mechanism where:
- Token prices increase as more tokens are bought
- Token prices decrease as tokens are sold back to the curve
- All trades happen against the bonding curve contract, providing instant liquidity
- No need for traditional AMM pools or market makers during the initial phase
dumpz8FfmeKTUHg3WiZYTxwsFQAQSrCqpD4y474XBdR
- Built-in bonding curve provides instant liquidity
- No need to bootstrap liquidity pools
- Automated price discovery based on supply and demand
- Equal opportunity for all participants
- Transparent pricing algorithm
- No pre-mining or insider allocations
- Platform takes a small fee on each transaction
- Creator pays initialization fee to deploy tokens
- Fees fund platform development and maintenance
- Slippage protection for all trades
- Overflow protection in mathematical operations
- Comprehensive error handling
- Tokens can "graduate" from bonding curve to traditional AMM
- Happens when bonding curve is fully sold out
- Enables transition to decentralized trading
- BondingCurve Account: Stores token state and reserves
- Token Mint: Standard SPL token mint
- Associated Token Accounts: Hold tokens for users and bonding curve
- Global Fee Vault: Collects platform fees
- Metadata Account: Stores token name, symbol, and URI
Creator
βββ Creates Token Mint
βββ Initializes BondingCurve
βββ Pays initialization fee
βββ Sets token metadata
BondingCurve
βββ Holds token reserves
βββ Manages SOL reserves
βββ Tracks virtual reserves (for pricing)
βββ Handles buy/sell operations
βββ Emits trading events
Users
βββ Buy tokens from bonding curve
βββ Sell tokens back to bonding curve
βββ Pay trading fees
DumpFun uses both virtual and real reserves for optimal price discovery:
- Used for price calculations
- Start at higher values to create initial liquidity depth
- Determine the shape of the bonding curve
- Track actual on-chain holdings
- Used for validation and graduation logic
- Represent true token/SOL balances
Buy Price Calculation:
n = virtual_sol_reserves * virtual_token_reserves
i = virtual_sol_reserves + sol_amount
r = n / i + 1
tokens_received = virtual_token_reserves - rSell Price Calculation:
n = (token_amount * virtual_sol_reserves) / (virtual_token_reserves + token_amount)
fee = n * fee_basis_points / 10_000
sol_received = n - fee- Early trades: Lower prices due to high virtual token reserves
- Later trades: Higher prices as virtual token reserves decrease
- Graduation: When all real tokens are sold, curve is complete
src/
βββ lib.rs # Main program entry point
βββ constants.rs # Platform constants and configuration
βββ contexts.rs # Account contexts for instructions
βββ errors.rs # Custom error definitions
βββ state.rs # Account state structures
βββ utils.rs # Helper functions
βββ instructions/
βββ initialize.rs # Token creation logic
βββ buy.rs # Token purchase logic
βββ sell.rs # Token selling logic
// Token Economics (from constants/bonding.rs)
pub const TOTAL_TOKEN_SUPPLY: u64 = 1_000_000_000 * 1_000_000; // 1B tokens with 6 decimals
pub const VIRTUAL_SOL_RESERVES: u64 = 30 * 1_000_000_000; // 30 SOL (30 billion lamports)
pub const VIRTUAL_TOKEN_RESERVES: u64 = 1_073_000_000 * 1_000_000; // 1.073B tokens
pub const REAL_SOL_RESERVES: u64 = 0; // Starts at 0 lamports
pub const REAL_TOKEN_RESERVES: u64 = 793_100_000 * 1_000_000; // 793.1M tokens
// Fees (from constants/fees.rs)
pub const FEE_BPS: u64 = 100; // 1% trading fee
pub const TOKEN_INITIALISATION_FEE: u64 = 1_000_000_000 / 20; // 0.05 SOL
pub const DEF_SLIPPAGE_BPS: u64 = 50; // 0.5% default slippage
// Seeds (from constants/seeds.rs)
pub const BONDING_CURVE: &str = "bonding_curve";
pub const GLOBAL_FEE_VAULT: &str = "global_fee_vault";
pub const MINT_AUTHORITY: &str = "mint_authority";
pub const METADATA: &str = "metadata";Creates a new token with bonding curve mechanics.
Parameters:
name: String- Token namesymbol: String- Token symboluri: String- Metadata URI
Process:
- Validates creator has sufficient funds for initialization fee
- Creates token metadata using Metaplex standard
- Mints total supply to bonding curve account
- Initializes bonding curve state
- Transfers initialization fee to global fee vault
- Emits initialization event
Accounts Required:
creator- Token creator (signer, pays fees)mint- Token mint accountmint_authority- PDA controlling mintbonding_curve- Bonding curve state accountassociated_bonding_curve- Token account for bonding curveglobal_fee_vault- Fee collection accountmetadata- Token metadata account
Purchases tokens from the bonding curve.
Parameters:
amount_in_sol: u64- SOL amount to spendslippage_basis_points: Option<u64>- Maximum acceptable slippage
Process:
- Calculates trading fee from SOL amount
- Determines tokens to receive based on net SOL
- Applies slippage protection
- Transfers tokens to buyer
- Transfers net SOL to bonding curve
- Transfers fees to global fee vault
- Updates bonding curve state
- Checks for graduation condition
- Emits buy event
Price Impact:
- More SOL spent = higher price per token
- Virtual reserves adjust to reflect new market state
- Real reserves track actual holdings
Sells tokens back to the bonding curve.
Parameters:
amount: u64- Token amount (exact tokens or percentage)is_percentage: bool- Whether amount is percentage or exactslippage_basis_points: Option<u64>- Maximum acceptable slippage
Process:
- Calculates actual tokens to sell
- Validates user has sufficient token balance
- Determines SOL to receive (after fees)
- Applies slippage protection
- Transfers tokens from user to bonding curve
- Transfers SOL from bonding curve to user
- Transfers fees to global fee vault
- Updates bonding curve state
- Emits sell event
Percentage Selling:
amount = 5000withis_percentage = truesells 50% of holdingsamount = 1000000withis_percentage = falsesells exactly 1M tokens
pub struct BondingCurve {
pub creator: Pubkey, // Token creator
pub mint: Pubkey, // Token mint address
pub authority: Pubkey, // Mint authority PDA
pub real_sol_reserves: u64, // Actual SOL held
pub real_token_reserves: u64, // Actual tokens held
pub virtual_sol_reserves: u64, // Virtual SOL for pricing
pub virtual_token_reserves: u64, // Virtual tokens for pricing
pub total_token_supply: u64, // Total token supply
pub is_bonding_curve_complete: bool, // Graduation status
}Key Methods:
get_buy_price(amount: u64) -> u64- Calculates tokens for SOL amountget_sell_price(amount: u64, fee_bps: u64) -> u64- Calculates SOL for token amountis_ready_for_graduation() -> bool- Checks if all tokens are sold
Virtual Reserves:
- Used exclusively for price calculations
- Create smooth bonding curve shape
- Allow for predictable price discovery
Real Reserves:
- Track actual on-chain balances
- Used for transaction validation
- Determine graduation status
State Updates:
- Buy: Decrease virtual token reserves, increase virtual SOL reserves
- Sell: Increase virtual token reserves, decrease virtual SOL reserves
- Always maintain mathematical consistency
All operations emit comprehensive events for off-chain tracking:
pub struct OnInitializeEvent {
pub creator: Pubkey,
pub mint: Pubkey,
pub bonding_curve: Pubkey,
pub associated_bonding_curve: Pubkey,
pub name: String,
pub symbol: String,
pub uri: String,
pub virtual_sol_reserves: u64,
pub virtual_token_reserves: u64,
pub real_sol_reserves: u64,
pub real_token_reserves: u64,
pub timestamp: i64,
}pub struct OnBuyEvent {
pub buyer: Pubkey,
pub mint: Pubkey,
pub sol_spent: u64,
pub tokens_received: u64,
pub fee_paid: u64,
pub virtual_sol_reserves: u64,
pub virtual_token_reserves: u64,
pub real_sol_reserves: u64,
pub real_token_reserves: u64,
pub is_bonding_curve_complete: bool,
pub timestamp: i64,
}pub struct OnSellEvent {
pub seller: Pubkey,
pub mint: Pubkey,
pub tokens_sold: u64,
pub sol_received: u64,
pub fee_paid: u64,
pub virtual_sol_reserves: u64,
pub virtual_token_reserves: u64,
pub real_sol_reserves: u64,
pub real_token_reserves: u64,
pub timestamp: i64,
}Event Usage:
- Track all trading activity
- Build price charts and analytics
- Monitor bonding curve health
- Detect graduation events
- Calculate volume and fees
- All amounts checked for overflow
- Slippage parameters validated
- Token balances verified before operations
- Reserve sufficiency confirmed
- 128-bit integers used for intermediate calculations
- Overflow protection in price calculations
- Division by zero prevention
- Minimum viable amounts enforced
- Only token creators can initialize tokens
- Mint authority controlled by PDA
- Users can only sell their own tokens
- Fee vault access restricted
pub enum Errors {
InsufficientFunds, // Not enough SOL/tokens
BondingCurveComplete, // Trading after graduation
SlippageExceeded, // Price moved too much
MathOverflow, // Calculation overflow
InvalidPercentage, // Invalid percentage value
InsufficientTokenBalance, // Not enough tokens to sell
InvalidAmount, // Zero or negative amount
InsufficientReserves, // Bonding curve lacks reserves
}- Rate: 1% (100 basis points) on all trades
- Buy trades: Fee deducted from SOL amount before token calculation
- Sell trades: Fee deducted from SOL received
- Collection: Automatically sent to global fee vault
- Amount: 0.05 SOL per token launch
- Purpose: Prevents spam token creation
- Payment: Required upfront from token creator
- Default: 0.5% (50 basis points)
- Purpose: Protects against price movement during transaction
- Customizable: Users can specify their own slippage tolerance
All fees collected in global fee vault can be used for:
- Platform development and maintenance
- Community incentives and rewards
- Marketing and growth initiatives
- Infrastructure costs
Before working with DumpFun, you'll need to set up your Solana development environment. Follow the comprehensive installation guide at:
π Anchor Installation Guide
This will walk you through installing:
- Rust - Programming language for Solana programs
- Solana CLI - Command-line tools for Solana development
- Anchor Framework - Solana development framework
- Node.js & Yarn - For running tests and frontend integration
After installation, verify your setup:
# Check Rust version
rustc --version
# Check Solana CLI
solana --version
# Check Anchor CLI
anchor --version
# Check Node.js
node --versionSet up your Solana environment:
# Set cluster (devnet for testing)
solana config set --url devnet
# Generate a new keypair (if needed)
solana-keygen new
# Check your address and balance
solana address
solana balanceOnce prerequisites are installed:
Once prerequisites are installed:
- Clone and Setup
git clone https://github.com/AdedigbaOluwad1/dumpfun.git
cd dumpfun- Install Dependencies
# Install Node.js dependencies for tests
npm install
# or
yarn install- Build Program
anchor build- Run Tests
# Copy environment template
cp .env.example .env
# Edit .env file with your private keys
# WALLET_PRIVATE_KEY="" - Your main wallet private key (base58 encoded)
# RECIPIENT_PRIVATE_KEY="" - Test recipient wallet private key (base58 encoded)
# Run the test suite
anchor testEnvironment Setup:
- The tests require private keys in base58 format
WALLET_PRIVATE_KEYis used as the token creator and trader in testsRECIPIENT_PRIVATE_KEYcan be used for multi-user test scenarios
- Deploy to Devnet
anchor deploy --provider.cluster devnet- Deploy to Mainnet
anchor deploy --provider.cluster mainnet-betaUpdate Anchor.toml with your program ID and cluster settings:
[programs.devnet]
dumpfun = "dumpz8FfmeKTUHg3WiZYTxwsFQAQSrCqpD4y474XBdR"
[programs.mainnet]
dumpfun = "dumpz8FfmeKTUHg3WiZYTxwsFQAQSrCqpD4y474XBdR"Install Dependencies:
npm install @coral-xyz/anchor @solana/web3.js @solana/spl-tokenBasic Setup:
import { Program, AnchorProvider, web3 } from '@coral-xyz/anchor';
import { PublicKey, Connection } from '@solana/web3.js';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const programId = new PublicKey('dumpz8FfmeKTUHg3WiZYTxwsFQAQSrCqpD4y474XBdR');Initialize Token:
async function initializeToken(
creator: Keypair,
name: string,
symbol: string,
uri: string
) {
const mint = Keypair.generate();
await program.methods
.initialize(name, symbol, uri)
.accounts({
creator: creator.publicKey,
mint: mint.publicKey,
// ... other accounts
})
.signers([creator, mint])
.rpc();
}Buy Tokens:
async function buyTokens(
buyer: Keypair,
mint: PublicKey,
amountInSol: number,
slippageBps?: number
) {
await program.methods
.buy(new BN(amountInSol * LAMPORTS_PER_SOL), slippageBps)
.accounts({
buyer: buyer.publicKey,
mint: mint,
// ... other accounts
})
.signers([buyer])
.rpc();
}Sell Tokens:
async function sellTokens(
seller: Keypair,
mint: PublicKey,
amount: number,
isPercentage: boolean,
slippageBps?: number
) {
await program.methods
.sell(new BN(amount), isPercentage, slippageBps)
.accounts({
seller: seller.publicKey,
mint: mint,
// ... other accounts
})
.signers([seller])
.rpc();
}Bonding Curve PDA:
const [bondingCurve] = PublicKey.findProgramAddressSync(
[Buffer.from('bonding_curve'), mint.toBuffer()],
programId
);Mint Authority PDA:
const [mintAuthority] = PublicKey.findProgramAddressSync(
[Buffer.from('mint_authority')],
programId
);Global Fee Vault PDA:
const [globalFeeVault] = PublicKey.findProgramAddressSync(
[Buffer.from('global_fee_vault')],
programId
);// Listen for buy events
const listener = program.addEventListener('OnBuyEvent', (event) => {
console.log('Buy event:', {
buyer: event.buyer.toString(),
mint: event.mint.toString(),
solSpent: event.solSpent.toNumber(),
tokensReceived: event.tokensReceived.toNumber(),
isComplete: event.isBondingCurveComplete
});
});
// Remove listener when done
program.removeEventListener(listener);Run the test suite:
anchor testThe test suite covers:
- Token initialization with various parameters
- Buy operations with different amounts and slippage
- Sell operations with exact amounts and percentages
- Error conditions and edge cases
- Event emission verification
- State consistency checks
- Mathematical accuracy validation
import 'dotenv/config';
import * as anchor from '@coral-xyz/anchor';
import { Program } from '@coral-xyz/anchor';
import { Dumpfun } from '../target/types/dumpfun';
import { BN } from 'bn.js';
import {
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
} from '@solana/web3.js';
import {
createInitializeMintInstruction,
getMinimumBalanceForRentExemptMint,
MINT_SIZE,
TOKEN_PROGRAM_ID,
} from '@solana/spl-token';
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
describe('dumpfun', () => {
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.dumpfun as Program<Dumpfun>;
const mint = Keypair.generate();
const creator = Keypair.fromSecretKey(
bs58.decode(process.env.WALLET_PRIVATE_KEY)
);
it('should initialize a mint, bonding curve, and mint tokens to the bonding curve!', async () => {
const [mintAuthorityPDA] = PublicKey.findProgramAddressSync(
[Buffer.from('mint_authority')],
program.programId
);
// Create mint account
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: creator.publicKey,
newAccountPubkey: mint.publicKey,
space: MINT_SIZE,
lamports: await getMinimumBalanceForRentExemptMint(
anchor.AnchorProvider.env().connection
),
programId: TOKEN_PROGRAM_ID,
});
// Initialize mint
const initializeMintInstruction = createInitializeMintInstruction(
mint.publicKey,
6, // 6 decimals
mintAuthorityPDA,
null,
TOKEN_PROGRAM_ID
);
// Initialize token with metadata
const tx = await program.methods
.initialize(
'Solana Gold',
'GOLDSOL',
'https://53cso10vyy.ufs.sh/f/0zLYHmgdOsEGYF3WHmI7jv08b2BZmzpuEFaAiQNHXKsgrPTD'
)
.accounts({
creator: creator.publicKey,
mint: mint.publicKey,
tokenMetadataProgram: new PublicKey(
'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
),
})
.preInstructions([createAccountInstruction, initializeMintInstruction])
.signers([creator, mint])
.rpc({ skipPreflight: true });
console.log('Token creation transaction signature:', tx);
});
it('should buy 1 SOL worth of tokens from the bonding curve', async () => {
const tx = await program.methods
.buy(
new BN(1 * LAMPORTS_PER_SOL), // 1 SOL in lamports
new BN(50) // 0.5% slippage tolerance
)
.accounts({
mint: mint.publicKey,
buyer: creator.publicKey,
})
.signers([creator])
.rpc({ skipPreflight: true });
console.log('Token purchase transaction signature:', tx);
});
it('should sell 100% of tokens back to the bonding curve', async () => {
const tx = await program.methods
.sell(
new anchor.BN(10_000), // 10,000 basis points = 100%
true, // amount is percentage
new anchor.BN(50) // 0.5% slippage tolerance
)
.accounts({
mint: mint.publicKey,
seller: creator.publicKey,
})
.signers([creator])
.rpc({ skipPreflight: true });
console.log('Token sale transaction signature:', tx);
});
});The test suite demonstrates the complete lifecycle:
- Initialization: Creates mint account, sets up bonding curve, mints total supply
- Buying: Purchases 1 SOL worth of tokens with 0.5% slippage protection
- Selling: Sells 100% of holdings back to bonding curve
- Environment Setup: Uses dotenv for private key management
- Account Creation: Manually creates mint account with proper rent exemption
- Metadata Integration: Sets up token metadata using Metaplex standard
- Error Handling: Uses
skipPreflight: truefor development testing - Comprehensive Coverage: Tests all three main instructions
We welcome contributions to DumpFun! Please see our contributing guidelines and submit pull requests for any improvements.
This project is licensed under the MIT License - see the LICENSE file for details.
This smart contract is provided as-is. Users should conduct their own audits and due diligence before using in production. Trading cryptocurrencies involves substantial risk of loss.
Built with β€οΈ on Solana