
Company News
AWS Security Hub Adds Socket for Supply Chain Security
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.
@juiceswapxyz/launchpad
Advanced tools
Production-ready token launchpad with bonding curve mechanism, secure metadata support, and automatic DEX graduation for Citrea
Token launchpad with bonding curve mechanism and automatic DEX graduation for JuiceSwap on Citrea.
npm install @juiceswapxyz/launchpad
Tokens launch on a constant-product bonding curve. When fully sold, they automatically graduate to JuiceSwap V2 with permanently locked liquidity.
0xdead (permanent lock)| Export | Description |
|---|---|
TokenFactoryABI | ABI for creating tokens and querying factory |
BondingCurveTokenABI | ABI for buy/sell/graduate operations |
ADDRESS | Contract addresses by chain ID |
LAUNCHPAD_CONSTANTS | Protocol constants (supply, reserves, fees) |
getAddresses(chainId) | Helper to get addresses for a chain |
isChainSupported(chainId) | Check if chain is supported |
import { TokenFactoryABI, ADDRESS } from '@juiceswapxyz/launchpad';
import { getContract } from 'viem';
const factory = getContract({
address: ADDRESS[5115].factory, // Citrea Testnet
abi: TokenFactoryABI,
client: publicClient,
});
const hash = await factory.write.createToken([
'My Token',
'MTK',
'ipfs://QmW2WQi7j6c7UgJTarActp7tDNikE4B2qXtFCfLPdsgaTQ'
]);
All tokens MUST include metadata when created. Metadata provides essential token information (logo, description, social links) and is immutable after creation.
IPFS (Recommended)
ipfs://Qm...Arweave
ar://...HTTPS (Not Recommended)
The metadata follows the OpenSea Metadata Standard:
{
"name": "My Awesome Token",
"description": "A revolutionary token launching on Citrea with fair bonding curve distribution",
"image": "ipfs://QmImageHash.../logo.png",
"external_url": "https://mytoken.com",
"attributes": [
{ "trait_type": "Category", "value": "Meme" },
{ "trait_type": "Network", "value": "Citrea" }
],
"properties": {
"website": "https://mytoken.com",
"twitter": "https://twitter.com/mytoken",
"telegram": "https://t.me/mytoken",
"discord": "https://discord.gg/mytoken"
}
}
Required Fields:
| Field | Type | Description |
|---|---|---|
name | string | Token name (should match on-chain name) |
description | string | Token purpose and value proposition (100-500 chars recommended) |
image | URI | Logo/avatar (512x512px PNG/SVG, IPFS recommended) |
Optional Fields:
external_url - Project websiteattributes - Categorical traits for filtering (e.g., Category, Network, Launch Type)properties - Social links and additional metadata (twitter, telegram, discord, whitepaper, etc.)The contract enforces these validation rules:
| Field | Maximum | Validation |
|---|---|---|
| Name | 100 characters | No control characters (0x00-0x1F, 0x7F), allows Unicode |
| Symbol | 20 characters | Uppercase A-Z and 0-9 only |
| Metadata URI | 1,024 bytes | No control characters |
Forbidden Characters:
\x00)\x01-\x1F) - newline, tab, escape codes, etc.\x7F)Allowed:
What the contract validates:
What the contract does NOT validate:
Note: Metadata is immutable after token creation (prevents rug pulls). Content validation is the responsibility of frontends and indexers.
Option 1: Pinata (Easiest)
QmImageHash...)metadata.json with image URI: ipfs://QmImageHash...metadata.json → copy metadata hash (e.g., QmMetadataHash...)ipfs://QmMetadataHash...Option 2: IPFS CLI
# Upload image
ipfs add logo.png
# Returns: QmImageHash...
# Create metadata.json
cat > metadata.json <<EOF
{
"name": "My Token",
"description": "Token description here",
"image": "ipfs://QmImageHash..."
}
EOF
# Upload metadata
ipfs add metadata.json
# Returns: QmMetadataHash...
import { TokenFactoryABI, ADDRESS } from '@juiceswapxyz/launchpad';
// After uploading metadata to IPFS
const metadataURI = "ipfs://QmMetadataHash...";
const hash = await factory.write.createToken([
'My Awesome Token',
'MAT',
metadataURI
]);
// Fetch metadata from IPFS using public gateway
async function fetchMetadata(uri: string) {
if (uri.startsWith('ipfs://')) {
const hash = uri.replace('ipfs://', '');
const url = `https://ipfs.io/ipfs/${hash}`;
const response = await fetch(url);
return await response.json();
}
if (uri.startsWith('ar://')) {
const id = uri.replace('ar://', '');
const url = `https://arweave.net/${id}`;
const response = await fetch(url);
return await response.json();
}
// HTTPS - direct fetch
return await fetch(uri).then(r => r.json());
}
Tip: Use multiple IPFS gateways for reliability (ipfs.io, cloudflare-ipfs.com, gateway.pinata.cloud).
✅ Use IPFS for permanent, decentralized storage ✅ Include all required fields (name, description, image) ✅ Add social links in properties for community discovery ✅ Use high-quality images (512x512px minimum, PNG/SVG) ✅ Pin IPFS content to ensure availability (use Pinata, Infura, Web3.Storage) ✅ Test metadata before deploying token ❌ Don't use HTTPS for production (centralized, can disappear) ❌ Don't include sensitive info in metadata (all public)
Can I update metadata after token creation? No. Metadata is immutable to prevent rug pulls and maintain trust.
What if my IPFS content becomes unavailable? Pin your content on multiple IPFS nodes or use pinning services (Pinata, Infura, Web3.Storage).
Does the contract validate my JSON structure? No. Only the URI format is validated. Content validation (JSON parsing, required fields) is the responsibility of frontends and indexers.
What image formats and sizes are supported? PNG and SVG are recommended. Keep file size under 500KB. Minimum 512x512px for logos. Animated PNGs (APNG) and animated SVGs are supported.
| Contract | Description |
|---|---|
TokenFactory.sol | Factory using EIP-1167 minimal proxies |
BondingCurveToken.sol | ERC20 with bonding curve and graduation |
| Parameter | Value | Description |
|---|---|---|
| Total Supply | 1,000,000,000 | Fixed supply per token |
| Virtual Token Reserves | 1,073,000,000 | For pricing curve |
| Virtual Base Reserves | Configurable (default 4,500 JUSD) | Initial virtual liquidity |
| Real Token Reserves | 793,100,000 | 79.31% sold on curve |
| Reserved for DEX | 206,900,000 | 20.69% for V2 LP |
| Fee | 1% (100 bps) | On input (buy) / output (sell) |
Buy (fee from input):
baseInAfterFee = baseIn - (baseIn * 1%)
tokensOut = virtualTokenReserves - (k / (virtualBaseReserves + baseInAfterFee))
Sell (fee from output):
baseOutBeforeFee = virtualBaseReserves - (k / (virtualTokenReserves + tokensIn))
baseOut = baseOutBeforeFee - (baseOutBeforeFee * 1%)
Where k = virtualBaseReserves * virtualTokenReserves
Triggered when realTokenReserves == 0 (all tokens sold from curve).
0xdeadfeeRecipient at graduationcontracts/
├── BondingCurveToken.sol
├── TokenFactory.sol
└── mocks/ # Test mocks only
exports/
├── index.ts # Barrel export
├── address.config.ts # Chain addresses
├── constants.ts # Protocol constants
└── abis/
├── TokenFactory.ts
└── BondingCurveToken.ts
test/
├── BondingCurveToken.test.ts
├── TokenFactory.test.ts
├── Graduation.test.ts
└── integration/ # Fork tests
scripts/
├── deploy.ts
└── exportAbis.ts
Copy .env.example to .env and set:
PRIVATE_KEY=
CITREA_TESTNET_RPC=https://rpc.testnet.citrea.xyz
CITREA_MAINNET_RPC=https://rpc.mainnet.citrea.xyz
# Optional
FEE_RECIPIENT= # Defaults to deployer
INITIAL_VIRTUAL_BASE=4500 # Virtual base reserves in JUSD
Note: Most addresses (JUSD, V2 Router, INIT_CODE_HASH) are now auto-imported from
@juicedollar/jusdand@juiceswapxyz/sdk-corepackages.
npm install
npm run compile # Compile contracts
npm test # Run unit tests
npm run test:coverage # Run with coverage
npm run test:fork # Run tests on local testnet fork
npm run test:integration:fork # Run integration tests on local testnet fork
npm run deploy:fork # Deploy to local testnet fork
npm run deploy:testnet # Deploy to Citrea Testnet
npm run deploy:mainnet # Deploy to Citrea Mainnet
npm run build # Build npm package (exports ABIs)
Fork Networks:
For local development with real contract state, use fork networks:
# Fork Citrea Testnet locally (uses real JUSD, V2 Router, etc.)
npx hardhat run scripts/deploy.ts --network forkTestnet
# Fork Citrea Mainnet locally
npx hardhat run scripts/deploy.ts --network forkMainnet
After deploying contracts, update exports/address.config.ts with the new addresses from your deployment output:
// Citrea Testnet
5115: {
factory: "0x...", // TokenFactory address
implementation: "0x...", // BondingCurveToken implementation
baseAsset: "0x...", // JUSD address (from @juicedollar/jusd)
router: "0x...", // JuiceSwap V2 Router (from @juiceswapxyz/sdk-core)
feeRecipient: "0x...", // Fee recipient (usually deployer)
initCodeHash: "0x...", // V2 factory init code hash (from @juiceswapxyz/sdk-core)
},
After updating addresses, build and publish:
npm run build # Export ABIs + bundle package
npm publish --access public
To manually export ABIs without publishing:
npm run ts:export:abis # Export ABIs only
npm run build # Export ABIs + bundle package
BondingCurveToken.sol - bonding curve logic, graduation mechanismTokenFactory.sol - proxy deploymentminTokensOut / minBaseOutMIT
FAQs
Production-ready token launchpad with bonding curve mechanism, secure metadata support, and automatic DEX graduation for Citrea
The npm package @juiceswapxyz/launchpad receives a total of 1 weekly downloads. As such, @juiceswapxyz/launchpad popularity was classified as not popular.
We found that @juiceswapxyz/launchpad demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.

Research
/Security News
Popular npm packages keyv and cacheable compromised.

Security News
A misconfiguration gave three Anthropic models internet access, and one, believing it was in a simulation, shipped a credential-stealing package to PyPI.