Overview
zpad is a launchpad and a payout engine. Every coin it launches is paired with Zcash, Monero or Litecoin on Solana and carries a 3% creator fee. Instead of going to the launcher, that fee is split between the people holding the coin, every hour, and paid out natively on privacy chains.
How it works
Five stages. The last four repeat forever.
- 01
Launch
onceA visitor submits a name, ticker, image and pair. zpad pins the metadata to IPFS, takes a keypair ending in zpad from its pool, and creates the coin on pump.fun with a 3% creator fee. zpad pays the network fee.
- 02
Trade
every tradeEvery buy and sell on the bonding curve (and on PumpSwap after graduation) pays the creator fee in the pair coin. It lands in a vault owned by that coin’s own derived creator key.
- 03
Snapshot
:00 UTCAt the top of every hour zpad snapshots every wallet holding at least 1,000 tokens, before touching the vault — so nobody can buy in after seeing the pot.
- 04
Split
:00 UTCThe vault is swept. XMR and LTC fees are swapped into Solana ZEC through Jupiter. 60% is credited to holders pro-rata; dust rolls forward.
- 05
Claim
any timeA holder signs one plain message. NEAR Intents delivers their balance natively as ZEC, ALEO, DASH or LTC to an address on that chain.
vercel cron 0 * * * * → /api/cron/collect
for each live coin:
1. snapshotHolders(mint) # who holds, right now
2. collectCreatorFee(mint) # sweep the coin's own vault
3. swapToZec(amount) # XMR / LTC pairs only, via Jupiter
4. creditHolders(pot, snapshot) # 60% pro-rata, dust carried
5. record(signature) # public on /distributionsFees & the split
3% of every trade is collected. 60% of that goes to holders; the rest pays for free launches and payout network fees.
- Creator fee · 3%
- $1,500
- Holder pot · 60%
- $900
- Your payout this hour
- $9.00
- ≈ 0.00620 ZEC
The split uses integer math on base units. Every share is rounded down, so the protocol never pays out more than it collected, and whatever rounds away is carried into the next hour’s pot.
const CREATOR_FEE_BPS = 300n // 3% of every trade
const COMMUNITY_BPS = 6000n // 60% of what is collected
function split(collected, holders, carry) {
const pot = (collected * COMMUNITY_BPS) / 10_000n + carry
const circulating = holders.reduce((s, h) => s + h.amount, 0n)
let paid = 0n
const credits = holders.map((h) => {
const share = (pot * h.amount) / circulating // floor division, never overpays
paid += share
return { wallet: h.owner, amount: share }
})
return { credits, carry: pot - paid } // dust rolls into the next hour
}Who gets paid
Only people. Programs and zpad itself are filtered out on chain.
- Wallets holding at least 1,000 tokens at the snapshot.
- The bonding curve, AMM pools and lockers are skipped: their owners are off-curve program addresses.
- zpad’s treasury and the coin’s own creator key are skipped.
- Several token accounts owned by one wallet count as one holder.
// Runs every hour, BEFORE the vault is swept.
const accounts = await connection.getProgramAccounts(tokenProgram, {
filters: [{ memcmp: { offset: 0, bytes: mint } }], // token accounts of this mint
dataSlice: { offset: 32, length: 40 }, // owner (32) + amount (8)
})
const byOwner = new Map()
for (const { account } of accounts) {
const owner = account.data.subarray(0, 32)
const amount = account.data.readBigUInt64LE(32)
if (amount === 0n) continue
if (!PublicKey.isOnCurve(owner)) continue // curve, pools, lockers: skipped
const key = new PublicKey(owner).toBase58()
if (key === treasury || key === creator) continue // zpad's own wallets: skipped
byOwner.set(key, (byOwner.get(key) ?? 0n) + amount) // many accounts → one wallet
}
const holders = [...byOwner].filter(([, amt]) => amt >= 1_000n * 1_000_000n)Claiming
Claims open at 0.002 ZEC. You always claim the whole balance, in one coin, to one address.
To claim, your wallet signs this exact text. The server rebuilds it from the request and checks the ed25519 signature against your address. It expires after 10 minutes and the amount must equal your available balance to the base unit.
zpad: claim Zcash
Send my holder earnings as native ZEC through NEAR Intents.
wallet: 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU
pay in: ZEC
to: u1qg…your-shielded-address
amount: 0.018432 ZEC
issued: 2026-09-29T12:00:00.000Zconst NAMES = { ZEC: "Zcash", ALEO: "Aleo", DASH: "Dash", LTC: "Litecoin" }
function claimMessage({ wallet, payout, to, amount, issuedAt }) {
const zec = (Number(amount) / 1e8).toFixed(8).replace(/0+$/, "").replace(/\.$/, "")
return [
`zpad: claim ${NAMES[payout]}`,
"",
`Send my holder earnings as native ${payout} through NEAR Intents.`,
"",
`wallet: ${wallet}`,
`pay in: ${payout}`,
`to: ${to}`,
`amount: ${zec} ZEC`,
`issued: ${issuedAt}`,
].join("\n")
}import bs58 from "bs58"
const wallet = window.phantom.solana
const { publicKey } = await wallet.connect()
const address = publicKey.toBase58()
const to = "u1qg…your-shielded-address"
// 1. Read the balance and get a live NEAR Intents quote.
const { balance } = await fetch(`/api/claim?wallet=${address}`).then((r) => r.json())
const quote = await fetch("/api/claim/preview", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ wallet: address, payout: "ZEC", to }),
}).then((r) => r.json())
// 2. Sign the exact claim message. This is not a transaction.
const intent = {
wallet: address,
payout: "ZEC",
to,
amount: balance.available,
issuedAt: new Date().toISOString(),
}
const { signature } = await wallet.signMessage(
new TextEncoder().encode(claimMessage(intent)),
"utf8",
)
// 3. Submit. zpad verifies the signature, then pays through NEAR Intents.
const claim = await fetch("/api/claim", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ ...intent, signature: bs58.encode(signature) }),
}).then((r) => r.json())
console.log(`${quote.amountOut} arriving in ~${claim.eta}s`)API reference
Public, keyless JSON. Amounts are strings of Solana-ZEC base units (8 decimals).
| Endpoint | |
|---|---|
| GET/api/claim?wallet=Balance, per-coin earnings and claim history for a Solana wallet. | Balance, per-coin earnings and claim history for a Solana wallet. |
| POST/api/claim/previewLive NEAR Intents quote for the whole balance. Validates the payout address. | Live NEAR Intents quote for the whole balance. Validates the payout address. |
| POST/api/claimSigned claim. Pays the whole balance in the chosen coin. | Signed claim. Pays the whole balance in the chosen coin. |
| GET/api/payouts?limit=Public ledger: hourly distributions and deliveries, newest first (max 100). | Public ledger: hourly distributions and deliveries, newest first (max 100). |
| GET/api/coins/:mint/candles?tf=OHLCV candles in USD from pump.fun. 1m, 5m, 15m, 1h, 4h, 1d. | OHLCV candles in USD from pump.fun. 1m, 5m, 15m, 1h, 4h, 1d. |
| GET/api/coins/:mint/tradesLast 50 buys and sells. | Last 50 buys and sells. |
| GET/api/search?q=Find live coins by ticker, name or mint prefix. | Find live coins by ticker, name or mint prefix. |
| POST/api/launchLaunch a coin. Same limits as the website. | Launch a coin. Same limits as the website. |
Check earnings
curl "https://www.zpad.sh/api/claim?wallet=7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"{
"wallet": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"balance": {
"earned": "1843200",
"claimed": "0",
"available": "1843200",
"min": "200000"
},
"perCoin": [ … ],
"claims": [ … ]
}Payout ledger
curl "https://www.zpad.sh/api/payouts?limit=20"Market data
# tf = 1m | 5m | 15m | 1h | 4h | 1d
curl "https://www.zpad.sh/api/coins/<mint>/candles?tf=1h"Launch a coin
IMG=$(base64 -w0 logo.png)
curl -X POST "https://www.zpad.sh/api/launch" \
-H "content-type: application/json" \
-d '{
"name": "Shielded Cat",
"symbol": "SCAT",
"description": "Holders earn Zcash.",
"quote": "ZEC",
"twitter": "https://x.com/shieldedcat",
"imageType": "image/png",
"imageBase64": "'"$IMG"'"
}'
# → { "mint": "…zpad", "signature": "…" }Pairs: ZEC (ZEC), XMR (XMR (wrapped)), LTC (cbLTC). Images must be PNG, JPEG, GIF or WebP under 4 MB. Twitter links must be on x.com or twitter.com.
Errors
Every error is JSON: { "error": "human readable message" }.
- 400
- Bad input: wallet, ticker, image, payout address, or balance below the minimum claim.
- 401
- Signature does not match the wallet, or it is older than 10 minutes.
- 404
- Unknown coin.
- 409
- Balance changed since you signed, or a claim with this signature is already on its way.
- 429
- Launch limit reached: 2 per visitor per 24 hours, or the daily site cap.
- 502
- The launch transaction did not land. The address goes back to the pool.
- 503
- Temporarily unavailable: address pool empty, gas tank or payout wallet being topped up.
Parameters
- Pairs
- ZEC, XMR (wrapped), LTC (cbLTC) on Solana
- Payout coins
- ZEC, ALEO, DASH, LTC (native)
- Creator fee
- 3% of every trade
- Holder share
- 60% of collected fees
- Snapshot
- Hourly at :00 UTC
- Minimum holding
- 1,000 tokens
- Minimum claim
- 0.002 ZEC
- Signature validity
- 10 minutes
- Free launches
- 2 per visitor per day
- Settlement
- NEAR Intents
FAQ
Do I need a wallet to launch?
No. zpad signs and pays for the launch. The coin’s creator key is derived per coin by zpad, so the fee vault belongs to the coin, not to the launcher.
Does the person who launched earn more?
Only if they hold. Launchers are paid like any other holder, by balance at the snapshot.
Why is everything counted in ZEC?
Fees from XMR and LTC pairs are swapped into Solana ZEC each hour so every balance is one unit. You pick the coin you receive when you claim.
Can I be paid in Monero?
Not today. Monero can be a pair, but NEAR Intents cannot deliver native XMR, so it is not a payout option.
What does signing the claim message do?
It proves you control the wallet that earned the balance. It is not a transaction, moves nothing and costs nothing.
What if a payout fails?
NEAR Intents refunds to zpad and your balance is restored automatically. You can claim again.