Developer Docs

← Back to index

This section is for developers integrating with ZecPad's on-chain program or building tools on top of ZecPad data. It assumes familiarity with Solana, Anchor, and @solana/web3.js.

Pre-release notice: ZecPad's bonding-curve program has not been deployed to mainnet-beta and has not completed a security audit (see Security & Audits). Program IDs, account layouts, and instruction signatures below reflect the current design and are subject to change before mainnet launch. Do not build production integrations against them yet — treat this section as an implementation preview, not a stable interface.

Program IDs

ProgramClusterAddress
zecpad_launchpadmainnet-betaNot yet deployed
zecpad_launchpaddevnetNot yet deployed

Once deployed, addresses will be published here and verifiable against the program's on-chain source hash. ZecPad's program relies on, but does not fork or replace, these standard programs:

DependencyAddress
SPL Token-2022TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Metaplex Token MetadatametaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s

Anchor IDL

The IDL will be published alongside the mainnet deployment and mirrored at idl/zecpad_launchpad.json in the program repository. Until then, the instruction set below reflects the current program design.

Instructions

create_token

Creates the SPL Token-2022 mint, initializes its BondingCurve account, and (via CPI) creates its Metaplex metadata account.

ParameterTypeDescription
namestringToken display name
symbolstringTicker
uristringMetadata JSON URI (image, description, socials)
supplyu64Total supply, minted once
curve_shapeenum { Steep, Linear, Flat }Sets initial virtual reserve ratio
migration_target_lamportsu64Real SOL reserves at which migration triggers
dev_buy_lamportsu64Optional same-transaction buy amount for the creator

enable_privacy_mode

CPI into SPL Token-2022 to initialize the ConfidentialTransferMint extension on the token's mint. Must be called at create_token time — Privacy Mode cannot be added to an existing public token after launch.

ParameterTypeDescription
auto_approve_new_accountsboolWhether new confidential accounts are auto-approved
auditor_elgamal_pubkeyOption<ElGamalPubkey>Optional auditor key with transfer-amount decrypt capability

buy

Buys tokens against the curve's constant-product formula.

ParameterTypeDescription
sol_amountu64Lamports to spend
min_tokens_outu64Slippage guard — transaction fails if the quote is worse

Enforces the per-wallet/per-transaction anti-bot limits described in Bonding Curve & Tokenomics via an AntibotTracker PDA keyed by (mint, wallet).

sell

Symmetric to buy: burns/returns tokens to the curve, returns SOL to the seller net of the trading fee.

ParameterTypeDescription
token_amountu64Tokens to sell
min_sol_outu64Slippage guard

migrate_liquidity

Permissionless — callable by anyone once the curve's real SOL reserves meet migration_target_lamports. Halts curve trading, deposits liquidity into a new Raydium/Orca pool via CPI, and revokes the mint authority.

claim_creator_fee / withdraw_platform_fee

Withdraw accrued trading-fee shares from, respectively, the token's CreatorVault PDA and the platform's treasury.

Reading program state

All state is stored in plain Anchor accounts and is readable by anyone without special access:

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

const [bondingCurvePda] = PublicKey.findProgramAddressSync(
  [Buffer.from("bonding_curve"), mint.toBuffer()],
  ZECPAD_PROGRAM_ID
);

const curve = await program.account.bondingCurve.fetch(bondingCurvePda);
// curve.virtualSolReserves, curve.virtualTokenReserves,
// curve.realSolReserves, curve.tokensSold, curve.status

Subscribing to trade events

The program emits Anchor events (TradeEvent, TokenCreatedEvent, MigrationEvent) rather than requiring log parsing:

const listenerId = program.addEventListener("TradeEvent", (event, slot) => {
  console.log(event.mint.toBase58(), event.side, event.solAmount.toString());
});

// later
program.removeEventListener(listenerId);

For production indexing, prefer a Geyser plugin or a managed webhook provider (e.g. Helius) over onLogs/addEventListener on a public RPC — see the RPC guidance below for why.

Example: creating a token client-side

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

const mint = Keypair.generate();

await program.methods
  .createToken({
    name: "Veilcoin",
    symbol: "VEIL",
    uri: "https://example.com/veilcoin.json",
    supply: new anchor.BN(1_000_000_000),
    curveShape: { steep: {} },
    migrationTargetLamports: new anchor.BN(85 * anchor.web3.LAMPORTS_PER_SOL),
    devBuyLamports: new anchor.BN(0.5 * anchor.web3.LAMPORTS_PER_SOL),
  })
  .accounts({ mint: mint.publicKey, creator: wallet.publicKey /* … */ })
  .signers([mint])
  .rpc();

RPC rate limits and provider guidance

Public RPC endpoints (api.mainnet-beta.solana.com, api.devnet.solana.com) are rate-limited and, in the case of the public mainnet-beta endpoint, actively reject cross-origin browser requests from unrecognized origins (you will see an HTTP 403 with {"error":{"code":403,"message":"Access forbidden"}}). This is not a bug in your integration — it's expected behavior of the public endpoint, and it means:

  • Never ship a browser dApp pointed at the public mainnet-beta RPC. Use a provider with a browser-safe API key and CORS support — Helius, Triton, QuickNode, or Alchemy all offer Solana RPC with free tiers suitable for development.
  • The public devnet RPC does allow browser CORS requests and is fine for local development and testing against devnet-deployed programs.
  • Set your RPC endpoint via environment variable (NEXT_PUBLIC_SOLANA_RPC_URL) rather than hardcoding it, so it can be swapped between devnet and a production provider without a code change.
  • For any indexing or webhook use case, prefer a managed Geyser/webhook provider over polling getProgramAccounts — the latter is expensive and frequently disabled entirely on public and even some paid RPC tiers.

Next