Skip to main content

Program IDs

JustPump consists of two main programs for token launching and trading.
Launchpad Program:
TBD
AMM Program:
TBD
Mainnet deployment pending. Use devnet for development and testing.

Quick Start

What You Can Do

Create Tokens

Launch new tokens with bonding curves

Buy/Sell

Trade on bonding curves before graduation

Swap

Trade graduated tokens on JustSwap AMM

Query State

Read token info, prices, and liquidity

Creating a Token

Create a new token with bonding curve trading enabled immediately.

Instruction: create_coin

Parameters:
  • name (string): Token name, max 32 characters
  • symbol (string): Token symbol, max 10 characters
  • uri (string): Metadata URI (JSON), max 200 characters
  • vanity_nonce (u64): Nonce for vanity mint address (must result in ‘JP’ prefix)
Key Accounts:
  • creator (signer, writable): Your wallet
  • mint (PDA): Token mint address - derive with ["mint", creator, vanity_nonce]
  • coin (PDA): Coin metadata - derive with ["coin", mint]
  • bonding_curve (PDA): Bonding curve state - derive with ["bonding-curve", mint]
Fees: Only transaction fee (~0.01 SOL), no creation fee

Example

import * as anchor from "@coral-xyz/anchor";
import { PublicKey } from "@solana/web3.js";

const LAUNCHPAD_PROGRAM_ID = new PublicKey(
  "3cFH7XveLjWZehiAfFeWYKEnch2n6NzCxYAVvRNEwhTq",
);

// Find vanity nonce that creates mint starting with 'JP'
let vanityNonce = 0;
let mint;
do {
  [mint] = PublicKey.findProgramAddressSync(
    [
      Buffer.from("mint"),
      creator.publicKey.toBuffer(),
      Buffer.from([vanityNonce]),
    ],
    LAUNCHPAD_PROGRAM_ID,
  );
  vanityNonce++;
} while (!mint.toBase58().startsWith("JP"));

// Derive PDAs
const [coin] = PublicKey.findProgramAddressSync(
  [Buffer.from("coin"), mint.toBuffer()],
  LAUNCHPAD_PROGRAM_ID,
);

const [bondingCurve] = PublicKey.findProgramAddressSync(
  [Buffer.from("bonding-curve"), mint.toBuffer()],
  LAUNCHPAD_PROGRAM_ID,
);

// Create token
await program.methods
  .createCoin(
    "My Token",
    "MTKN",
    "https://arweave.net/your-metadata-hash",
    vanityNonce - 1,
  )
  .accounts({
    creator: creator.publicKey,
    mint,
    coin,
    bondingCurve,
    // ... see full account list in IDL
  })
  .signers([creator])
  .rpc();
Token metadata should follow Metaplex standards. Upload JSON to Arweave or IPFS first.

Buying Tokens (Bonding Curve)

Buy tokens on the bonding curve before graduation.

Instruction: buy_exact_quote_in

Parameters:
  • spendable_quote_in (u64): Maximum SOL to spend (in lamports)
  • min_tokens_out (u64): Minimum tokens to receive (slippage protection)
Key Accounts:
  • buyer (signer, writable): Your wallet
  • mint: Token mint address
  • coin (PDA): Derive with ["coin", mint]
  • bonding_curve (PDA): Derive with ["bonding-curve", mint]
  • buyer_quote: Your WSOL token account
  • buyer_token: Your token account for the mint
Fees: 1.3% total (60 BPS platform, 50 BPS creator, 20 BPS insurance)

Example

const solAmount = 1_000_000_000; // 1 SOL
const slippage = 0.01; // 1%

// Calculate minimum tokens with slippage
const expectedTokens = calculateBondingCurveOutput(
  solAmount,
  bondingCurveState,
);
const minTokensOut = Math.floor(expectedTokens * (1 - slippage));

await program.methods
  .buyExactQuoteIn(new anchor.BN(solAmount), new anchor.BN(minTokensOut))
  .accounts({
    buyer: buyer.publicKey,
    mint,
    coin,
    bondingCurve,
    buyerQuote: buyerWsolAccount,
    buyerToken: buyerTokenAccount,
    // ... see full account list in IDL
  })
  .signers([buyer])
  .rpc();
You need to wrap SOL to WSOL first using SystemProgram.transfer + Token.syncNative.

Selling Tokens (Bonding Curve)

Sell tokens on the bonding curve. Limited to 10% of circulating supply per transaction.

Instruction: sell_on_curve

Parameters:
  • tokens_in (u64): Amount of tokens to sell
Key Accounts:
  • seller (signer, writable): Your wallet
  • mint: Token mint address
  • coin (PDA): Derive with ["coin", mint]
  • bonding_curve (PDA): Derive with ["bonding-curve", mint]
  • seller_token: Your token account
  • seller_quote: Your WSOL token account
Constraint: tokens_in <= (bonding_curve.tokens_sold * 1000) / 10000 (10% max)

Example

const tokensToSell = 100_000_000_000; // 100 tokens with 9 decimals

// Check 10% constraint
const bondingCurveData = await program.account.bondingCurve.fetch(bondingCurve);
const maxSell = (bondingCurveData.tokensSold * 1000n) / 10000n;

if (BigInt(tokensToSell) > maxSell) {
  throw new Error(`Exceeds 10% max sell. Max: ${maxSell}`);
}

await program.methods
  .sellOnCurve(new anchor.BN(tokensToSell))
  .accounts({
    seller: seller.publicKey,
    mint,
    coin,
    bondingCurve,
    sellerToken: sellerTokenAccount,
    sellerQuote: sellerWsolAccount,
    // ... see full account list in IDL
  })
  .signers([seller])
  .rpc();
Selling more than 10% of circulating supply will fail. Split large sells into multiple transactions.

Swapping on JustSwap (AMM)

Trade graduated tokens on the constant product AMM.

Instruction: swap_quote_for_base (SOL → Token)

Parameters:
  • quote_in (u64): Amount of SOL to swap (in lamports)
  • min_base_out (u64): Minimum tokens to receive (slippage protection)
Key Accounts:
  • trader (signer, writable): Your wallet
  • pool (PDA): Derive with ["pool", base_mint, quote_mint]
  • trader_quote: Your WSOL account
  • trader_base: Your token account

Instruction: swap_base_for_quote (Token → SOL)

Parameters:
  • base_in (u64): Amount of tokens to swap
  • min_quote_out (u64): Minimum SOL to receive (slippage protection)
Key Accounts: Same as above, reversed Fees: 1.3% total (same as bonding curve)

Example

const AMM_PROGRAM_ID = new PublicKey(
  "56Sx4pQJYsksMBNo75KXctKfTvvsBrrdfZCAiJS91SDK",
);

// Derive pool PDA
const [pool] = PublicKey.findProgramAddressSync(
  [Buffer.from("pool"), baseMint.toBuffer(), quoteMint.toBuffer()],
  AMM_PROGRAM_ID,
);

// Swap SOL for tokens
const quoteAmount = 500_000_000; // 0.5 SOL
const poolData = await ammProgram.account.pool.fetch(pool);

// Calculate output with constant product formula: dy = (y * dx) / (x + dx)
const dx = quoteAmount * 0.987; // After 1.3% fee
const dy = (poolData.baseReserve * dx) / (poolData.quoteReserve + dx);
const minBaseOut = Math.floor(dy * 0.99); // 1% slippage

await ammProgram.methods
  .swapQuoteForBase(new anchor.BN(quoteAmount), new anchor.BN(minBaseOut))
  .accounts({
    trader: trader.publicKey,
    pool,
    traderQuote: traderWsolAccount,
    traderBase: traderTokenAccount,
    // ... see full account list in IDL
  })
  .signers([trader])
  .rpc();

PDA Derivations

All Program Derived Addresses use deterministic seeds.

Launchpad Program PDAs

const LAUNCHPAD = new PublicKey("3cFH7XveLjWZehiAfFeWYKEnch2n6NzCxYAVvRNEwhTq");

// Global config
const [globalConfig] = PublicKey.findProgramAddressSync(
  [Buffer.from("global")],
  LAUNCHPAD,
);

// Coin metadata
const [coin] = PublicKey.findProgramAddressSync(
  [Buffer.from("coin"), mint.toBuffer()],
  LAUNCHPAD,
);

// Bonding curve
const [bondingCurve] = PublicKey.findProgramAddressSync(
  [Buffer.from("bonding-curve"), mint.toBuffer()],
  LAUNCHPAD,
);

// Vanity mint (must start with 'JP')
const [mint] = PublicKey.findProgramAddressSync(
  [Buffer.from("mint"), creator.toBuffer(), Buffer.from([nonce])],
  LAUNCHPAD,
);

// Token vaults
const [vaultToken] = PublicKey.findProgramAddressSync(
  [Buffer.from("vault-token"), mint.toBuffer()],
  LAUNCHPAD,
);

const [vaultQuote] = PublicKey.findProgramAddressSync(
  [Buffer.from("vault-quote"), mint.toBuffer()],
  LAUNCHPAD,
);

AMM Program PDAs

const AMM = new PublicKey("56Sx4pQJYsksMBNo75KXctKfTvvsBrrdfZCAiJS91SDK");

// AMM config
const [ammConfig] = PublicKey.findProgramAddressSync(
  [Buffer.from("amm-config")],
  AMM,
);

// Pool
const [pool] = PublicKey.findProgramAddressSync(
  [Buffer.from("pool"), baseMint.toBuffer(), quoteMint.toBuffer()],
  AMM,
);

// Pool vaults
const [poolVaultBase] = PublicKey.findProgramAddressSync(
  [Buffer.from("pool-vault-base"), baseMint.toBuffer(), quoteMint.toBuffer()],
  AMM,
);

const [poolVaultQuote] = PublicKey.findProgramAddressSync(
  [Buffer.from("pool-vault-quote"), baseMint.toBuffer(), quoteMint.toBuffer()],
  AMM,
);

Reading State

Fetch on-chain data to display prices, liquidity, and token info.

Get Token Info

// Fetch coin metadata
const coinData = await program.account.coin.fetch(coin);

console.log({
  name: coinData.name,
  symbol: coinData.symbol,
  creator: coinData.creator.toBase58(),
  status: coinData.status, // { onCurve: {} } | { readyToMigrate: {} } | { migrated: {} }
  totalSupply: coinData.totalSupply.toString(),
  ammPool: coinData.ammPool?.toBase58() || null,
});

Get Bonding Curve State

// Fetch bonding curve data
const curveData = await program.account.bondingCurve.fetch(bondingCurve);

console.log({
  tokensSold: curveData.tokensSold.toString(),
  collectedQuote: curveData.collectedQuote.toString(), // SOL collected
  virtualSolReserves: curveData.virtualSolReserves.toString(),
  virtualTokenReserves: curveData.virtualTokenReserves.toString(),
});

// Calculate current price
const price =
  (curveData.virtualSolReserves * 1e9) / curveData.virtualTokenReserves;
console.log(`Current price: ${price} SOL per token`);

Get Pool State

// Fetch AMM pool data
const poolData = await ammProgram.account.pool.fetch(pool);

console.log({
  baseReserve: poolData.baseReserve.toString(),
  quoteReserve: poolData.quoteReserve.toString(),
  canonical: poolData.canonical,
  creator: poolData.creator.toBase58(),
});

// Calculate current price
const price = (poolData.quoteReserve * 1e9) / poolData.baseReserve;
console.log(`Current price: ${price} SOL per token`);

Token Programs

Token-2022

Program ID: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEbUsed For: All user-created tokensFeatures: Metadata Extension support

SPL Token

Program ID: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DAUsed For: WSOL (quote token) and LP tokensStandard: Original SPL Token program

Common Errors

ErrorCauseSolution
ExceedsMaxSellImpactTrying to sell > 10% of supplySplit into multiple transactions
SlippageExceededPrice moved beyond min outputIncrease slippage tolerance
NotReadyToMigrateTrying to migrate < 85 SOLWait until 85 SOL collected
AlreadyMigratedToken already graduatedUse AMM swap instead of bonding curve
InvalidVanityMintMint doesn’t start with ‘JP’Iterate vanity nonce until valid

Helper Functions

Calculate Bonding Curve Output

function calculateBondingCurveOutput(
  solIn: number,
  curve: { virtualSolReserves: BN; virtualTokenReserves: BN },
): number {
  const k = curve.virtualSolReserves.mul(curve.virtualTokenReserves);
  const newSolReserves = curve.virtualSolReserves.add(new BN(solIn));
  const newTokenReserves = k.div(newSolReserves);
  const tokensOut = curve.virtualTokenReserves.sub(newTokenReserves);

  // Apply 1.3% fee
  return tokensOut.muln(987).divn(1000).toNumber();
}

Calculate AMM Output

function calculateAmmOutput(
  amountIn: number,
  reserveIn: BN,
  reserveOut: BN,
): number {
  // Constant product: x * y = k
  // dy = (y * dx) / (x + dx)

  // Apply 1.3% fee
  const amountInWithFee = Math.floor(amountIn * 0.987);

  const numerator = reserveOut.muln(amountInWithFee);
  const denominator = reserveIn.addn(amountInWithFee);

  return numerator.div(denominator).toNumber();
}

Resources


Support

For developer support: