npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@juiceswapxyz/launchpad

v2.1.0

Published

Production-ready token launchpad with bonding curve mechanism, secure metadata support, and automatic DEX graduation for Citrea

Readme

@juiceswapxyz/launchpad

Token launchpad with bonding curve mechanism and automatic DEX graduation for JuiceSwap on Citrea.

Installation

npm install @juiceswapxyz/launchpad

Overview

Tokens launch on a constant-product bonding curve. When fully sold, they automatically graduate to JuiceSwap V2 with permanently locked liquidity.

  • All tokens trade against JUSD (Juice Dollar)
  • Graduation creates TOKEN/JUSD pairs on JuiceSwap V2
  • LP tokens burned to 0xdead (permanent lock)

Frontend Integration

Exports

| 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 |

Usage

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'
]);

Token Metadata

All tokens MUST include metadata when created. Metadata provides essential token information (logo, description, social links) and is immutable after creation.

Storage Options

IPFS (Recommended)

  • Decentralized, content-addressed storage
  • Industry standard for token metadata
  • Format: ipfs://Qm...
  • Services: Pinata, Web3.Storage, Infura

Arweave

  • Permanent pay-once storage
  • Format: ar://...

HTTPS (Not Recommended)

  • Centralized, mutable, can disappear
  • Only use for testing

Metadata JSON Structure

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 website
  • attributes - Categorical traits for filtering (e.g., Category, Network, Launch Type)
  • properties - Social links and additional metadata (twitter, telegram, discord, whitepaper, etc.)

Security Constraints

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:

  • Null bytes (\x00)
  • Control characters (\x01-\x1F) - newline, tab, escape codes, etc.
  • DEL character (\x7F)

Allowed:

  • ASCII printable characters (0x20-0x7E) ✅
  • Unicode characters (emoji, international text) ✅
  • URL encoding (%, &, =) ✅

Contract Behavior

What the contract validates:

  • ✅ Metadata URI is non-empty
  • ✅ URI length ≤ 1KB
  • ✅ No control characters in URI
  • ✅ Name/symbol length limits
  • ✅ Symbol contains only A-Z, 0-9

What the contract does NOT validate:

  • ❌ URI format or reachability
  • ❌ JSON structure or content
  • ❌ Image existence or validity

Note: Metadata is immutable after token creation (prevents rug pulls). Content validation is the responsibility of frontends and indexers.

How to Upload Metadata

Option 1: Pinata (Easiest)

  1. Sign up at pinata.cloud
  2. Upload logo image → copy IPFS hash (e.g., QmImageHash...)
  3. Create metadata.json with image URI: ipfs://QmImageHash...
  4. Upload metadata.json → copy metadata hash (e.g., QmMetadataHash...)
  5. Use metadata hash when creating token: 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...

Creating a Token

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
]);

Fetching Metadata in Frontend

// 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).

Best Practices

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)

FAQ

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.

Contracts

| Contract | Description | |----------|-------------| | TokenFactory.sol | Factory using EIP-1167 minimal proxies | | BondingCurveToken.sol | ERC20 with bonding curve and graduation |

Bonding Curve

Constants

| 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) |

Formulas

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

Graduation

Triggered when realTokenReserves == 0 (all tokens sold from curve).

  1. Add liquidity: 206.9M tokens + collected JUSD to V2
  2. Burn LP tokens to 0xdead
  3. Transfer accumulated fees to fee recipient

Fees

  • 1% fee on all buy/sell transactions
  • Fees accumulate during bonding curve phase
  • Sent to feeRecipient at graduation

Repository Structure

contracts/
├── 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

Usage

Environment

Copy .env.example to .env and set:

PRIVATE_KEY=
CITREA_TESTNET_RPC=https://rpc.testnet.citrea.xyz
CITREA_MAINNET_RPC=https://rpc.citrea.xyz
UNISWAP_V2_ROUTER=           # JuiceSwap router
BASE_ASSET_ADDRESS=          # JUSD address
INIT_CODE_HASH=              # V2 factory init code hash
FEE_RECIPIENT=               # Optional, defaults to deployer
INITIAL_VIRTUAL_BASE=4500    # Optional, in JUSD units

Commands

npm install
npm run compile          # Compile contracts
npm test                 # Run unit tests
npm run test:coverage    # Run with coverage
npm run test:integration:fork  # Run integration tests on 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)

Publishing

ABIs are automatically exported and the package is built before publishing via prepublishOnly.

npm run compile          # Compile contracts first (if changed)
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

Security

Audited Dependencies

  • OpenZeppelin Contracts v5.4.0 (ERC20, ReentrancyGuard, Ownable, Pausable, Clones)
  • Uniswap V2 Core/Periphery

Requires Audit

  • BondingCurveToken.sol - bonding curve logic, graduation mechanism
  • TokenFactory.sol - proxy deployment

Protections

  • Reentrancy guards on all state-changing functions
  • Slippage protection via minTokensOut / minBaseOut
  • Single initialization (proxy pattern)
  • Front-running protection (blocks transfers to V2 pair before graduation)

References

License

MIT