Skip to content

Turbin3/accel-Bond

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Accel-Bond

A permissionless token launchpad on Solana using a bonding curve AMM. Token prices adjust algorithmically based on supply and demand — no order books, no presales, no pre-mint.

Table of Contents


How It Works

  1. Create a Token — Anyone can launch a token by providing a name, symbol, and description. The frontend uploads the metadata to IPFS via Pinata, creating a Metaplex-compatible token metadata account on-chain. The program mints the full supply into a bonding curve vault. The creator deposits a small SOL seed (0.001 SOL) to initialize the curve's liquidity.

  2. Buy — Users send SOL to the bonding curve. The curve mints tokens to the buyer based on a constant-product formula. The SOL accumulates in the curve PDA.

  3. Sell — Users burn tokens back to the curve. The curve returns SOL from its reserves based on the same formula. The price decreases as tokens are sold back.

  4. Graduate — When the SOL in the curve reaches the graduation threshold (default: 85 SOL), the token graduates. A migration instruction deposits the accumulated SOL and remaining tokens into a Raydium CPMM liquidity pool.

The bonding curve acts as an automated market maker (AMM). The price per token increases on buys and decreases on sells, creating organic price discovery without external liquidity providers.


Architecture

┌─────────────────────────────────────────────────────┐
│                    Frontend (Next.js)                │
│  ┌──────────┐  ┌──────────┐  ┌───────────────────┐  │
│  │  Create   │  │   Buy    │  │       Sell        │  │
│  │  Token    │  │  Token   │  │       Token       │  │
│  └────┬─────┘  └────┬─────┘  └────────┬──────────┘  │
│       │              │                  │             │
│       └──────────────┼──────────────────┘             │
│                      │                                │
│            ┌─────────┴─────────┐                      │
│            │  Generated SDK    │                      │
│            │  (Codama)         │                      │
│            └─────────┬─────────┘                      │
└──────────────────────┼───────────────────────────────┘
                       │ Solana RPC
┌──────────────────────┼───────────────────────────────┐
│              On-Chain Program                         │
│                                                      │
│  ┌──────────────────────────────────────────────┐   │
│  │              GlobalConfig (PDA)               │   │
│  │  authority, fee_recipient, protocol_fee_bps,  │   │
│  │  graduation_threshold, is_paused              │   │
│  └──────────────────────────────────────────────┘   │
│                                                      │
│  ┌──────────────────────────────────────────────┐   │
│  │         BondingCurve (PDA per token)          │   │
│  │  mint, real_token_reserve, real_sol_reserve,  │   │
│  │  complete, pool_address                       │   │
│  └───────────────────┬──────────────────────────┘   │
│                      │                                │
│              ┌───────┴───────┐                        │
│              │   Vault (ATA)  │ ← holds token supply │
│              └───────────────┘                        │
│                                                      │
│  ┌──────────────────────────────────────────────┐   │
│  │    Metaplex Token Metadata (PDA per mint)     │   │
│  │  name, symbol, uri, update_authority          │   │
│  │  (wallets, explorers, and dApps read this)    │   │
│  └──────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────┘

Tech Stack

On-Chain (Rust)

Tool Purpose
Pinocchio Zero-dependency Solana smart contract framework. Replaces Anchor with raw syscall-level performance. No runtime overhead — programs compile to lean SBF bytecode.
Metaplex Token Metadata On-chain standard for token metadata (name, symbol, URI). Created via CPI during token creation. Enables wallet detection and display.
Shank Derive macros (#[derive(ShankType, ShankAccount)]) that extract instruction args and account structs from Rust source into a JSON IDL.
Codama Reads the Shank IDL and generates a fully-typed TypeScript client (encoders, decoders, PDAs, error types).
bytemuck Zero-copy serialization for #[repr(C)] structs. Accounts are read/written as typed references without deserialization overhead.
LiteSVM Lightweight in-process Solana VM for fast program testing without a full validator.

Frontend (TypeScript)

Tool Purpose
Next.js 15 React framework (App Router)
React 19 UI library
Tailwind CSS v4 Utility-first CSS
@solana/web3.js Solana RPC and transaction building
@solana/wallet-adapter Wallet connection (Phantom, Solflare, etc.)
Pinata IPFS pinning service for token metadata storage. Uploads JSON metadata (name, symbol, description) to IPFS before on-chain token creation.
pnpm Package manager
Lucide React Icons

IDL Generation (Shank)

Shank inspects Rust structs annotated with #[derive(ShankType)] and #[derive(ShankAccount)] to produce a JSON IDL at idl/bonding_curve.json.

// src/instructions/buy_token.rs
#[repr(C, packed)]
#[derive(Zeroable, Pod, Copy, Clone, ShankType)]  // ← Shank extracts this
pub struct BuyTokenArgs {
    pub amount_to_buy: u64,
    pub min_tokens_out: u64,
    pub bump: u8,
}

// src/state/bonding_curve.rs
#[repr(C)]
#[derive(Zeroable, Pod, Clone, Copy)]  // ← Account structs (no ShankAccount needed for bytemuck)
pub struct BondingCurve { ... }

The generated IDL (idl/bonding_curve.json) contains:

  • Instructions — discriminants, account layouts, arg types
  • Accounts — struct field definitions with types and offsets
  • Types — error enums, custom types
  • Metadata — program address

Known Shank limitation: When instruction args are defined as standalone structs (like BuyTokenArgs), Shank puts them in the types section and may leave args empty. The fix is to manually copy the struct fields into the args array of each instruction in the IDL. This project has already been patched.

Client SDK Generation (Codama)

Codama reads the Shank IDL and generates a type-safe TypeScript client in app/src/sdk/.

cd app
npx tsx generate-sdk.mts

The generator (app/generate-sdk.mts) uses @codama/nodes-from-anchor and @codama/renderers to produce:

app/src/sdk/
├── programs/
│   └── bondingCurve.ts        # Program address constant
├── instructions/
│   ├── index.ts               # Re-exports
│   ├── buyToken.ts            # Encoder + types for BuyToken
│   ├── sellToken.ts           # Encoder + types for SellToken
│   ├── createToken.ts         # Encoder + types for CreateToken
│   └── ...                    # Other instructions
├── accounts/
│   ├── index.ts
│   ├── bondingCurve.ts        # BondingCurve account decoder
│   └── globalConfig.ts        # GlobalConfig account decoder
├── types/
│   └── bondingCurveError.ts   # Error enum → TypeScript union
└── index.ts                   # Top-level re-exports

The frontend imports from this SDK for instruction encoding:

import { getBuyTokenInstructionDataEncoder } from "../src/sdk/instructions";

Regenerate after any program change:

  1. Update idl/bonding_curve.json (manually patch Shank's empty args if needed)
  2. Run npx tsx generate-sdk.mts
  3. Run pnpm exec tsc --noEmit to verify no type errors

On-Chain Program

Accounts

GlobalConfig — PDA(seed: "global_config")

Single instance. Stores protocol-wide settings.

Field Type Description
initialized u8 1 if initialized
authority [u8; 32] Admin pubkey (can update config)
total_token_supply [u8; 8] Total supply per token (raw, 1B × 10^6)
initial_real_sol_deposit [u8; 8] SOL (lamports) creator deposits on creation
fee_recipient [u8; 32] Receives protocol fees
protocol_fee_bps [u8; 2] Fee in basis points (default: 100 = 1%)
graduation_threshold_lamports [u8; 8] SOL threshold for graduation
migration_dex_program [u8; 32] Target DEX for migration
is_paused u8 Emergency pause flag
bump u8 PDA bump
_reserved [u8; 64] Reserved for future upgrades

Size: 189 bytes

BondingCurve — PDA(seed: "bonding_curve", mint)

One per token. Stores curve state. Token metadata (name, symbol, URI) lives in the Metaplex Token Metadata account.

Field Type Description
mint [u8; 32] SPL token mint address
token_owner [u8; 32] Creator pubkey
real_token_reserve [u8; 8] Tokens held by the curve (raw units)
real_sol_reserve [u8; 8] SOL in the curve (lamports)
total_token_supply [u8; 8] Total supply (raw units, constant)
created_at [u8; 8] Unix timestamp of creation
complete u8 1 if graduated
bump u8 PDA bump
pool_address [u8; 32] Raydium pool address (zeroed until migrated)

Size: 130 bytes

Instructions

Discriminant Name Description
0 InitializeGlobalConfig Create the global config PDA
1 CreateToken Launch a new token with bonding curve
2 UpdateFeeRecipient Change fee recipient (admin only)
3 UpdateBondingCurve Update supply/deposit params (admin only)
4 ToggleTrading Pause/resume all trading (admin only)
5 UpdateAuthority Transfer admin ownership (admin only)
6 BuyToken Buy tokens from the bonding curve
7 SellToken Sell tokens back to the bonding curve
8 Migrate Graduate to Raydium DEX pool

CreateToken

Accounts:
  [signer, writable]  creator
  []                  global_config
  [writable]          bonding_curve (PDA)
  [signer, writable]  mint
  [writable]          vault (curve's ATA)
  []                  system_program
  []                  token_program
  []                  associated_token_program
  [writable]          metadata (Metaplex Token Metadata PDA)
  []                  mpl_program (Metaplex Token Metadata program)

Args (variable-length after discriminator):
  bump: u8
  name_len: u8, name: [u8; name_len]       ← UTF-8 token name (max 32 bytes)
  symbol_len: u8, symbol: [u8; symbol_len] ← UTF-8 token symbol (max 10 bytes)
  uri_len: u16, uri: [u8; uri_len]         ← IPFS/Arweave metadata URI (max 200 bytes)

The program creates a Metaplex Token Metadata account via CPI during token creation. This enables wallets (Phantom, Solflare) and explorers to detect and display the token's name, symbol, and image.

The creator must have enough SOL for:

  • Rent-exempt balance for the bonding curve PDA (~0.003 SOL)
  • Rent-exempt balance for the mint account (~0.002 SOL)
  • Initial SOL deposit (default: 0.001 SOL)
  • Transaction fee

BuyToken

Accounts:
  [signer, writable]  buyer
  []                  mint
  [writable]          vault (curve's ATA)
  [writable]          buyer_ata
  [writable]          bonding_curve (PDA)
  []                  global_config
  [writable]          fee_recipient
  []                  system_program
  []                  token_program
  []                  associated_token_program

Args:
  amount_to_buy: u64     ← SOL in lamports
  min_tokens_out: u64    ← slippage protection (raw token units)
  bump: u8

SellToken

Accounts:
  [signer, writable]  seller
  []                  global_config
  [writable]          bonding_curve (PDA)
  [writable]          mint
  [writable]          seller_token_account
  [writable]          fee_recipient
  []                  token_program

Args:
  amount: u64        ← tokens to sell (raw units)
  min_sol_out: u64   ← slippage protection (lamports)

Bonding Curve Math

The program uses a constant-product formula with real reserves only (no virtual reserves).

Buy — given SOL input, calculate tokens received:

tokens_out = (sol_in × token_reserve) / (sol_reserve + sol_in)

Sell — given token input, calculate SOL returned:

sol_out = (tokens_in × sol_reserve) / (token_reserve + tokens_in)

Both formulas use u128 intermediate arithmetic to prevent overflow.

Since the sell formula only uses SOL that actually exists in the PDA, InsufficientReserves errors are impossible. The output is always ≤ the real SOL balance.

Example (with 0.001 SOL initial deposit and 1B token supply):

Action Input Output
Buy 0.1 SOL ~90.9B tokens
Buy 1 SOL ~500B tokens
Sell 100B tokens ~0.000167 SOL

Fee Model

  • Protocol fee: 1% (100 basis points), configurable by admin
  • Fee is calculated on each buy: fee = sol_amount × protocol_fee_bps / 10000
  • The full SOL amount transfers to the bonding curve PDA, then the fee portion moves to the fee recipient
  • No fee on sell (seller receives full output minus slippage)

Graduation & Migration

When real_sol_reserve ≥ graduation_threshold_lamports:

  1. The bonding curve's complete flag is set to 1
  2. Buying/selling is disabled on the curve
  3. The Migrate instruction can be called to:
    • Transfer remaining tokens and SOL to a Raydium CPMM pool
    • Set pool_address on the bonding curve

Frontend

Next.js 15 application with React 19, Tailwind CSS, and Solana wallet adapter.

Pages

Route Description
/ Home — shows latest token launches with progress bars
/create Token creation form (name, symbol, metadata)
/explore Browse all launched tokens with search
/trade/[address] Buy/sell interface for a specific token
/admin Protocol admin panel (initialize, update config, pause)

SDK

The TypeScript SDK is auto-generated by Codama from the IDL. Located in app/src/sdk/.

import { getBondingCurveAddress, getGlobalConfigAddress } from "./src/sdk/accounts";
import { getBuyTokenInstructionDataEncoder } from "./src/sdk/instructions";

Getting Started

Prerequisites

Build the Program

# Build for Solana SBF target
cargo build-sbf

# Output: target/deploy/bonding_curve.so

Run Tests

# Run all tests (single-threaded for LiteSVM compatibility)
cargo test -- --test-threads=1

Deploy

# Generate a new program keypair (or use existing)
solana-keygen new -o target/deploy/bonding_curve-keypair.json

# Fund the deployer wallet
solana airdrop 2 --url devnet

# Upload buffer and deploy
BUFFER=$(solana program write-buffer target/deploy/bonding_curve.so --url devnet | grep Buffer: | awk '{print $2}')
solana program deploy --program-id target/deploy/bonding_curve-keypair.json --buffer $BUFFER --url devnet

Initialize Global Config

After deploying, initialize the global config via the admin page or with a script:

cd app
# Run the initialization (creates the global_config PDA)
# Then open /admin to configure fee recipient, thresholds, etc.
pnpm run dev

Connect the deployer wallet on the /admin page. The first connected wallet becomes the authority.

Start the Frontend

cd app
pnpm install
pnpm run dev

Open http://localhost:3000.

Regenerate the SDK

If you modify the on-chain program's instructions or accounts:

cd app
# 1. Update idl/bonding_curve.json with the new struct definitions
# 2. Run the Codama generator
npx tsx generate-sdk.mts

Project Structure

accel-Bond/
├── Cargo.toml                    # Rust workspace config
├── src/
│   ├── lib.rs                    # Program entrypoint (entrypoint! macro)
│   ├── constant.rs               # Constants (seeds, fees, thresholds)
│   ├── errors.rs                 # Custom error enum
│   ├── utils.rs                  # Utility macros (check_ata!)
│   ├── state/
│   │   ├── mod.rs                # State module exports
│   │   ├── bonding_curve.rs      # BondingCurve struct + math
│   │   └── global_config.rs      # GlobalConfig struct
│   ├── instructions/
│   │   ├── mod.rs                # Instruction dispatcher
│   │   ├── init_global_config.rs # Create protocol config
│   │   ├── update_global_config.rs # Admin config updates
│   │   ├── create_token.rs       # Token + curve creation
│   │   ├── buy_token.rs          # Buy from curve
│   │   ├── sell_token.rs         # Sell back to curve
│   │   └── migrate_to_raydium.rs # Graduate to DEX
│   └── tests/
│       ├── mod.rs                # Core instruction tests
│       └── update_global_config.rs # Admin instruction tests
├── idl/
│   └── bonding_curve.json        # Shank-generated IDL
├── app/
│   ├── package.json
│   ├── next.config.ts
│   ├── generate-sdk.mts          # Codama SDK generator script
│   ├── lib/
│   │   └── solana.ts             # Core Solana helpers + encoder
│   ├── app/
│   │   ├── layout.tsx            # Root layout with wallet provider
│   │   ├── page.tsx              # Home page
│   │   ├── create/page.tsx       # Token creation
│   │   ├── explore/page.tsx      # Token browser
│   │   ├── trade/[address]/page.tsx # Trade page
│   │   ├── admin/page.tsx        # Admin panel
│   │   └── api/metadata/route.ts # Pinata IPFS metadata upload
│   ├── components/
│   │   ├── Header.tsx            # Navigation header
│   │   └── WalletContextProvider.tsx # Wallet adapter setup
│   └── src/sdk/                  # Auto-generated by Codama (DO NOT EDIT)
│       ├── index.ts
│       ├── programs/             # Program client
│       ├── instructions/         # Instruction encoders
│       ├── accounts/             # Account decoders
│       └── types/                # Shared types
└── .gitignore

Configuration

Global Config Parameters

Parameter Default Description
total_token_supply 1,000,000,000 × 10^6 Raw token supply per curve
initial_real_sol_deposit 0.001 SOL SOL creator deposits on creation
protocol_fee_bps 100 (1%) Fee on buys
graduation_threshold_lamports 85 SOL SOL required for graduation
is_paused false Emergency trading halt

Token Metadata

Token metadata is stored in a Metaplex Token Metadata account (not in the bonding curve). This ensures wallets and explorers can detect and display token information.

  • Name: Up to 32 bytes (UTF-8)
  • Symbol: Up to 10 bytes (UTF-8)
  • URI: Up to 200 bytes (IPFS or Arweave link to JSON metadata)
  • Decimals: 6 (standard SPL token)
  • Update Authority: Token creator (can update metadata later)

The frontend uploads metadata JSON to IPFS via Pinata before creating the on-chain token.

Environment Variables (Frontend)

NEXT_PUBLIC_SOLANA_RPC_URL=https://devnet.helius-rpc.com/?api-key=YOUR_KEY
PINATA_API_KEY=your_pinata_api_key
PINATA_SECRET_KEY=your_pinata_secret_key

PINATA_API_KEY and PINATA_SECRET_KEY are used for uploading token metadata JSON to IPFS. Get free keys from pinata.cloud.


SDK Usage

import { Connection, PublicKey } from "@solana/web3.js";
import {
  fetchAllBondingCurves,
  getBondingCurveAddress,
  getGlobalConfigAddress,
  buyToken,
  sellToken,
  createToken,
} from "./lib/solana";

const connection = new Connection("https://api.devnet.solana.com");

// Fetch all launched tokens
const curves = await fetchAllBondingCurves(connection);
curves.forEach(c => {
  console.log(`${c.name} (${c.symbol}) — ${c.mint}`);
  console.log(`  Liquidity: ${c.realSolReserve / 1e9} SOL`);
  console.log(`  Tokens available: ${c.realTokenReserve / 1e6}`);
});

// Get a specific curve
const { address } = await getBondingCurveAddress(mintPubkey);
const info = await connection.getAccountInfo(address);

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages