@blankdotbuild/sdk
v2.0.17
Published
Launch Solana tokens and manage staking/fee-allocation settings from your backend. Tokens created through the SDK behave exactly like ones launched on blank.build — same trading, discovery, fees, staking, buyback, and liquidity-compounding lifecycle.
Readme
@blankdotbuild/sdk
Launch Solana tokens and manage staking/fee-allocation settings from your backend. Tokens created through the SDK behave exactly like ones launched on blank.build — same trading, discovery, fees, staking, buyback, and liquidity-compounding lifecycle.
Full docs: https://blank.build/docs/for-developers
Install
npm install @blankdotbuild/sdk @solana/web3.js
# bun add / yarn add also workNode 20+ for server-side use.
Quick start
Get a secret key from Settings → API Keys at blank.build (max 3 active per account), then:
Before calling blank.launch.create(), upload your token image and metadata JSON to IPFS or Arweave and wait until the metadata is publicly readable. A successful Pinata/IPFS upload response is not enough by itself: gateway propagation can lag for a few seconds, and Blank validates the metadata during launch build.
import { Keypair } from "@solana/web3.js";
import {
createBlankClient,
createBlankKeypairWallet,
} from "@blankdotbuild/sdk";
const blank = createBlankClient({
baseUrl: "https://api.blank.build",
apiKey: process.env.BLANK_API_KEY,
});
const secretKey = Uint8Array.from(JSON.parse(process.env.SOLANA_SECRET_KEY!));
const wallet = createBlankKeypairWallet(Keypair.fromSecretKey(secretKey));
const result = await blank.launch.create(
{
name: "My Token",
symbol: "MYT",
metadataUri: "ipfs://bafy...", // public JSON, ipfs:// or ar://, <=72 bytes, no gateway URLs
antiSnipeEnabled: true,
staking: { shareBps: 2_000 }, // optional: 20% of creator fees → stakers
buybackBurn: { shareBps: 1_000 }, // optional: 10% → Auto Buyback and Burn
liquidityCompounding: { shareBps: 500 }, // optional: 5% → locked LP after graduation
},
wallet
);
console.log(result.mintAddress, result.submission.signature);That's it. The token is live, on the discovery feed, and trades on the bonding curve.
The API key is server-side only — never ship it to the browser. Wallet signatures still prove on-chain authority; the key just identifies your account for quota and attribution.
launch.create input
{
name: string; // ≤32 bytes, no reserved names
symbol: string; // ≤10 bytes, no reserved tickers
metadataUri: string; // ipfs:// or ar://, ≤72 bytes
antiSnipeEnabled?: boolean; // default false
staking?: { shareBps: number }; // optional, 100–10,000 bps
buybackBurn?: { shareBps: number }; // optional, 100–10,000 bps
liquidityCompounding?: { shareBps: number }; // optional, 100–10,000 bps
creatorFeeSplit?: Array<{ walletAddress: string; bps: number }>;
idempotencyKey?: string; // safe retry, dedup'd 24h
}creatorFeeSplit: 1–5 wallets, must total exactly 10,000 bps (100%).
staking.shareBps, buybackBurn.shareBps, and liquidityCompounding.shareBps: optional launch-time creator-side fee allocations. They cannot exceed 10,000 bps combined and are increase-only after launch.
Metadata readiness
metadataUri must already resolve to public JSON before launch build. The JSON must include an image URI. For bot launchers, the production-safe sequence is:
- Upload the image.
- Upload metadata JSON that points to that image.
- Poll a public gateway for the metadata CID until it returns HTTP 200 JSON with the expected
image. - Call
blank.launch.create()with the canonicalipfs://...orar://...URI.
Do not pass https://gateway.pinata.cloud/... or another gateway URL as metadataUri; use the canonical content URI after verifying it through a gateway.
Retrying after a failed submit
If the wallet signs but submit fails, or a Jito bundle is accepted but does not land before expiry, the SDK throws LaunchSubmissionFailedError with the signed transactions on it, so you can retry without re-prompting the wallet:
import { LaunchSubmissionFailedError } from "@blankdotbuild/sdk";
try {
await blank.launch.create(input, wallet);
} catch (err) {
if (err instanceof LaunchSubmissionFailedError) {
await blank.launch.retrySubmit({
submissionIntentId: err.submissionIntentId,
signedTransactions: err.signedTransactions,
});
} else {
throw err;
}
}All SDK errors extend BlankSdkError and expose code, status, and details.
Staking
Prefer enabling staking at launch with launch.create({ staking: { shareBps } }). If a token was launched without staking, the current token controller can enable it later:
await blank.staking.enable(
{ mint: result.mintAddress, stakingShareBps: 2_000 }, // 20% of creator fees → stakers
wallet
);Top up the staking pool with creator-funded SOL (needs ≥1 non-controller staker, max 10,000 SOL):
await blank.staking.topUp(
{ mint: result.mintAddress, amountLamports: 500_000_000n },
wallet
);Public reads (no API key)
await blank.fees.getStatus({ mint }); // creator, staking, buyback, and liquidity status
await blank.manifest.get(); // active program IDs, limitsPinning program IDs (optional, defense-in-depth)
If you want belt-and-suspenders protection against a compromised worker advertising different program IDs:
const blank = createBlankClient({
baseUrl: "https://api.blank.build",
apiKey: process.env.BLANK_API_KEY,
expected: {
programIds: {
dbc: "...",
staking: "...",
feeSplitter: "...",
tokenomics: "...",
},
launchSigner: "...",
},
});launch.create then verifies the manifest before any wallet prompt and throws MANIFEST_PROGRAM_ID_MISMATCH / MANIFEST_LAUNCH_SIGNER_MISMATCH on drift. It also refuses to sign any transaction whose required signer doesn't match (LAUNCH_SIGNER_MISMATCH), regardless of expected.
Browser wallets
Anything that exposes publicKey and Solana signing methods works as a wallet — most adapters (Phantom, Backpack, etc.) match the shape. Make sure it supports signAllTransactions, since launch bundles can include multiple transactions.
Not supported yet
- Browser-side launches (key must stay server-side)
- SDK-built creator fee-claim transactions; creators claim from the Blank dashboard
