Permissionless bonding-curve token launchpad on Base mainnet.
No admin keys Β· No rugs Β· Pure on-chain math Β· Auto-graduates to Uniswap V2
Live App Β· Contract (Basescan) Β· Docs Β· Contributing
- What is CurvePad?
- Features
- Architecture
- How the Math Works
- Deployed Contracts
- Getting Started
- Testing
- API Reference
- Security
- Contributing
- License
CurvePad lets anyone launch an ERC-20 token in a single transaction. Price is governed by a linear bonding curve enforced entirely on-chain β no liquidity pools, no market makers, no admin controls.
When a token's ETH reserve hits 10 ETH, anyone can call graduate(). The contract deploys all liquidity to a Uniswap V2 pool and permanently burns the LP tokens to the dead address (0x000...dEaD), locking liquidity forever.
| Property | Value |
|---|---|
| Chain | Base Mainnet (chain ID 8453) |
| Curve | Linear: price = 1e12 + 1e6 Γ supply_in_tokens wei |
| Creator fee | 1% of every buy and sell |
| Graduation threshold | 10 ETH in reserve |
| LP lock | Permanent β burned to 0x000...dEaD |
| Admin | None β fully immutable |
- Linear bonding curve with quadratic buy formula solved at full 256-bit precision
- Reserve invariant β ETH balance always equals β« price(s) ds, fully collateralized
- Automatic graduation β 10 ETH reserve β Uniswap V2 pool β LP tokens burned
- ReentrancyGuard on
buy()andsell() - CEI pattern throughout β state before external calls
- Permissionless β no owner, no pause, no upgrades
- π Explore β token grid with multicall batching (7 calls/token), search, sort, live stats
- π Launch β deploy a token in one transaction with image upload, social links, seed buy
- π Trade β Bloomberg-style terminal with bonding curve chart, depth chart, live event feed
- πΌ Portfolio β on-chain holdings via multicall, graduation progress bars
- π Graduation UI β real-time progress, timeline, celebration on threshold
- Image upload β token logos stored in Replit Object Storage via presigned GCS URLs
- Metadata API β Express server stores off-chain token metadata (description, socials, image)
- OpenAPI codegen β typed React hooks generated from OpenAPI spec via Orval
- pnpm workspace β monorepo with shared TypeScript project references
curvepad/
β
βββ artifacts/
β βββ curvepad/ # React + Vite frontend
β β βββ src/
β β βββ pages/
β β β βββ LandingPage.tsx
β β β βββ ExplorePage.tsx # Token grid, multicall batching
β β β βββ CreatePage.tsx # Deploy + image upload
β β β βββ TradePage.tsx # Bloomberg-style trading terminal
β β β βββ PortfolioPage.tsx # On-chain holdings
β β βββ components/
β β β βββ BondingCurveChart.tsx # Canvas price curve
β β β βββ PriceChart.tsx # Trade history chart
β β β βββ DepthChart.tsx # Buy/sell depth
β β β βββ ActivityFeed.tsx # Live Trade event stream
β β β βββ GraduationBar.tsx # Progress bar
β β β βββ GraduationTimeline.tsx # Milestone timeline
β β β βββ TerminalLog.tsx # macOS-style live terminal
β β βββ lib/
β β βββ web3.ts # ABI, factory address, math utils
β β βββ api.ts # Metadata API client
β β
β βββ api-server/ # Express metadata + image API
β βββ src/
β βββ routes/
β β βββ tokens.ts # Token metadata CRUD
β β βββ storage.ts # Image upload + serving
β βββ lib/
β βββ objectStorage.ts # GCS presigned URL helper
β βββ objectAcl.ts # Access control helpers
β
βββ contracts/foundry/ # Solidity contracts
β βββ src/
β β βββ TokenFactory.sol # Factory + BondingCurveToken
β βββ test/
β β βββ TokenFactory.t.sol # 20 Foundry tests
β βββ script/
β βββ DeployV2.s.sol
β
βββ lib/
βββ api-spec/ # OpenAPI spec (source of truth)
βββ api-client-react/ # Generated React query hooks
βββ api-zod/ # Generated Zod schemas
βββ object-storage-web/ # React hook + Uppy upload component
βββ db/ # Drizzle ORM schema + migrations
price(s) = BASE_PRICE + SLOPE Γ s
sβ total supply in full tokens (WAD-divided)BASE_PRICE=1e12wei (0.000001 ETH at supply 0)SLOPE=1e6wei per token (price grows as supply grows)
The contract ETH balance always equals the area under the curve:
reserve(s) = BASE_PRICE Γ s + SLOPE Γ sΒ² / 2
This invariant is enforced by the buy/sell math, not by admin controls.
Given ethForReserve (ETH after 1% fee is deducted), tokens minted x satisfy:
SLOPE/2 Β· xΒ² + B Β· x β ethForReserve = 0
x = (β(BΒ² + 2 Β· SLOPE Β· ethForReserve) β B) / SLOPE
where B = BASE_PRICE + SLOPE Γ currentSupply is the current spot price.
The discriminant is computed at full 256-bit precision β no premature WAD division β preventing catastrophic cancellation on small trades.
Selling x tokens returns gross = reserve(s) β reserve(s β x), less 1% fee.
if reserve >= 10 ETH:
anyone can call graduate()
β addLiquidityETH(reserve, freshMintedTokens) to Uniswap V2
β LP tokens sent to 0x000...dEaD (burned, permanent lock)
β buy() and sell() revert forever
| Field | Value |
|---|---|
| TokenFactory | 0x6EF504b98b4369C0a1aF4fD1885D7acCf843dDf6 |
| Deployer | 0xD034E94465Db1669f80D817c66e58cF194d027C8 |
| Deploy TX | 0x85681...3df05 |
| Block | 49276726 |
| Verified | β Basescan |
0x479596943e70316A0d893De1876EBeA1Ea8E4D5B β block 44809260, no graduation support.
- Node.js 20+
- pnpm 10+
- Foundry (for contract work)
git clone https://github.com/agunnaya001/curvepad
cd curvepad
pnpm installpnpm --filter @workspace/curvepad run dev
# β http://localhost:5173pnpm --filter @workspace/api-server run dev
# β http://localhost:3001/apiCreate a .env file (never commit it):
# Required for image upload (Replit Object Storage)
DEFAULT_OBJECT_STORAGE_BUCKET_ID=your-bucket-id
PRIVATE_OBJECT_DIR=your-private-dir
PUBLIC_OBJECT_SEARCH_PATHS=your-public-paths
# Required for the API server session
SESSION_SECRET=your-session-secret
# Required for contract deployment
PRIVATE_KEY=your-deployer-private-key
BASESCAN_API_KEY=your-basescan-keycd contracts/foundry
forge script script/DeployV2.s.sol \
--rpc-url https://mainnet.base.org \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--etherscan-api-key $BASESCAN_API_KEY \
-vvThen update FACTORY_ADDRESS in artifacts/curvepad/src/lib/web3.ts.
After editing lib/api-spec/openapi.yaml:
pnpm --filter @workspace/api-spec run codegencd contracts/foundry
forge test -v20 tests, all passing:
| # | Test | Coverage |
|---|---|---|
| 1 | test_createToken |
Factory deploys correctly |
| 2 | test_buyReturnsNonTrivialTokens |
Buy mints tokens |
| 3 | test_buyRequiresPayment |
Buy reverts with no ETH |
| 4 | test_sellReturnsETH |
Sell returns ETH |
| 5 | test_sellRevertsOnInsufficientBalance |
Sell guard |
| 6 | test_reserveInvariantAfterBuy |
Reserve math |
| 7 | test_reserveInvariantAfterSell |
Reserve math |
| 8 | test_creatorFeeIsDeducted |
1% fee routing |
| 9 | test_multipleTokensIndependent |
Factory isolation |
| 10 | test_buyAndSellRoundTrip |
Round-trip fidelity |
| 11 | test_graduateRevertsBeforeThreshold |
Threshold guard |
| 12 | test_graduateSucceedsAtThreshold |
State transition |
| 13 | test_buyBlockedAfterGraduation |
Post-grad lock |
| 14 | test_sellBlockedAfterGraduation |
Post-grad lock |
| 15 | test_graduateOnlyOnce |
Double-graduate guard |
| 16 | test_getGraduationInfoProgress |
Progress BPS |
| 17 | test_ethFullyDrainedAfterGraduation |
ETH β Uniswap |
| 18 | test_lpBurnedToDeadAddress |
LP burn verification |
| 19 | test_anyoneCanGraduate |
Permissionless graduation |
| 20 | test_fullGraduationLifecycle |
End-to-end lifecycle |
# Graduation tests only
forge test --match-test "graduation\|Graduate\|Graduated" -v
# With gas reporting
forge test --gas-reportpnpm run typecheckThe API server runs at /api. Full spec: lib/api-spec/openapi.yaml.
| Method | Path | Description |
|---|---|---|
GET |
/api/tokens |
List all token metadata records |
GET |
/api/tokens/:address |
Get metadata for a token |
POST |
/api/tokens |
Save token metadata (called after deploy) |
| Method | Path | Description |
|---|---|---|
POST |
/api/storage/uploads/request-url |
Get presigned GCS URL for image upload |
GET |
/api/storage/objects/:path |
Serve an uploaded image |
Upload flow:
POST /api/storage/uploads/request-urlwith{ name, size, contentType }β returns{ uploadURL, objectPath }PUTthe file directly touploadURL(direct to GCS, no server roundtrip)- Store
objectPathand display viaGET /api/storage/objects/:path
| Concern | Mitigation |
|---|---|
| Reentrancy | ReentrancyGuard on buy() and sell() |
| State ordering | CEI pattern β all state mutations before external calls |
| Admin risk | No owner, no pause, no upgrade proxy |
| Reserve solvency | Reserve invariant enforced by math, not governance |
| Precision | 256-bit discriminant; no WAD division before sqrt |
| LP rug | LP tokens burned to 0x000...dEaD on graduation |
| Overflow | Checked arithmetic (Solidity 0.8.x default) |
The contracts are not audited. Use at your own risk on mainnet.
See CONTRIBUTING.md for development setup, code style, and PR guidelines.
MIT β Β© 2024 CurvePad contributors.