Fan Token Launchpad Development
Fan tokens are not utility tokens in the classical sense, nor governance in DeFi understanding. They are a monetization tool for a fan audience which in 99% of cases is not crypto-native. A club wants to monetize loyalty, a fan wants a sense of belonging and exclusive privileges, the platform takes a commission. A fan token launchpad should serve this model — not permissionless DeFi, but managed onboarding for mass audiences.
Fan Token Launchpad Specifics vs Classical IDO Launchpad
A classical IDO launchpad works with crypto-native audiences: MetaMask, USDT, understanding of gas fees, risk tolerance. A fan token launchpad works with a fan who came from the club's mobile app and might be hearing the word "wallet" for the first time.
Key differences:
| Parameter | IDO Launchpad | Fan Token Launchpad |
|---|---|---|
| Audience | Crypto-native | Mainstream / sports fans |
| Onboarding | MetaMask + USDT | Email / social networks, fiat on-ramp |
| Token utility | Governance, yield | Voting for club, exclusive content |
| Pricing | Market-driven | Managed by club, bonding curve |
| Regulatory | DeFi grey area | Closer to securities in some jurisdictions |
| Secondary market | DEX | Managed AMM with liquidity control |
Token Architecture and Bonding Curve
Fan token mechanics
Chiliz-style fan tokens (FC Barcelona BAR, Juventus JUV) are built on several principles:
- Limited emission: fixed supply, controlled by the club
- Utility binding: voting, content access, NFT drops, player meetings
- Managed liquidity: club or platform controls liquidity, no permissionless AMM
- Fiat gateway: purchase with fiat via card or local payment methods
Bonding curve for primary sale
Instead of fixed pricing or Dutch auction, fan tokens often use a bonding curve — price rises as sales increase. This creates FOMO and rewards early buyers.
contract FanTokenBondingCurve {
IERC20 public immutable fanToken;
uint256 public immutable initialPrice; // first token price in USD (scaled 1e6)
uint256 public immutable slope; // curve steepness (scaled 1e18)
uint256 public tokensSold;
// Linear bonding curve: price = initialPrice + slope * supply
function getCurrentPrice() public view returns (uint256) {
return initialPrice + (slope * tokensSold / 1e18);
}
// Cost to buy amount tokens starting from current supply
function getBuyCost(uint256 amount) public view returns (uint256) {
// Integral of linear function: trapezoid area sum
uint256 priceAtStart = getCurrentPrice();
uint256 priceAtEnd = initialPrice + (slope * (tokensSold + amount) / 1e18);
return (priceAtStart + priceAtEnd) * amount / 2 / 1e6; // in base currency
}
function buy(uint256 tokenAmount, uint256 maxCost) external payable nonReentrant {
uint256 cost = getBuyCost(tokenAmount);
require(cost <= maxCost, "Price slippage exceeded");
require(msg.value >= cost, "Insufficient payment");
tokensSold += tokenAmount;
fanToken.safeTransfer(msg.sender, tokenAmount * 1e18);
// Return excess
if (msg.value > cost) {
payable(msg.sender).transfer(msg.value - cost);
}
emit TokensPurchased(msg.sender, tokenAmount, cost);
}
}
The initialPrice and slope parameters are configured for each club. Typical initial price range is $1–5, final price at full placement is $5–20.
Fiat Onboarding
This is the key difference between fan token launchpad and DeFi platforms. A fan shouldn't know about gas, they should click "Buy" and pay with their card.
Custody and custodial wallet
Two approaches to managing user wallets:
Fully custodial (Chiliz approach): platform holds private keys. User sees token balance but has no on-chain wallet. Maximum UX simplicity, minimum user requirements. Disadvantage: centralization, platform must comply with custody regulations.
MPC wallet (recommended approach): Multi-Party Computation wallet. Private key is split between user (via device/account) and platform. Neither side has the full key. User signs transactions via SDK without seeing raw private key. Platform doesn't hold full key — no custody risk.
MPC wallet-as-a-service providers: Privy, Dynamic, Web3Auth, Capsule. All support social login (Google, Apple, email).
// Privy integration — creating embedded wallet via social login
import { usePrivy, useWallets } from '@privy-io/react-auth';
function FanTokenPurchase() {
const { login, authenticated, user } = usePrivy();
const { wallets } = useWallets();
const embeddedWallet = wallets.find(w => w.walletClientType === 'privy');
async function purchaseTokens(amount: number) {
if (!authenticated) {
await login(); // Google/Apple/email login → automatically creates embedded wallet
return;
}
const provider = await embeddedWallet!.getEthereumProvider();
const walletClient = createWalletClient({
account: embeddedWallet!.address as `0x${string}`,
transport: custom(provider)
});
// User signs transaction via Privy UI — doesn't see raw tx
const hash = await walletClient.writeContract({
address: FAN_TOKEN_LAUNCHPAD_ADDRESS,
abi: LAUNCHPAD_ABI,
functionName: 'buyWithFiat',
args: [BigInt(amount), MAX_SLIPPAGE],
value: parseEther(await getETHCostForAmount(amount))
});
return hash;
}
return (
<button onClick={() => purchaseTokens(10)}>
{authenticated ? 'Buy 10 tokens' : 'Sign in and buy'}
</button>
);
}
Fiat-to-crypto conversion
User pays with fiat — platform converts to crypto and executes the transaction. Options:
On-ramp providers: Stripe Crypto (via Link), MoonPay, Transak, Ramp Network. Integrate via widget or API. Handle KYC/AML, support cards, bank transfers, Apple Pay.
// Transak integration for on-ramp
function initiateFiatPurchase(fanTokenAmount: number, userAddress: string) {
const transak = new Transak({
apiKey: process.env.TRANSAK_API_KEY,
environment: 'PRODUCTION',
defaultCryptoCurrency: 'ETH',
walletAddress: userAddress,
// Club customization
themeColor: '009900', // club color
hostURL: window.location.origin,
widgetHeight: '570px',
widgetWidth: '450px',
// Webhook for status tracking
webhookStatusUrl: `${API_BASE}/transak-webhook`,
});
transak.init();
// After successful on-ramp — automatically call purchase
transak.on(Transak.EVENTS.TRANSAK_ORDER_SUCCESSFUL, async (orderData) => {
await purchaseFanTokens(fanTokenAmount, userAddress, orderData.status.id);
});
}
Utility and Engagement Mechanics
A token without utility is meaningless on its own. The launchpad should include infrastructure for utility.
Club voting
contract FanVoting {
struct Vote {
string question;
string[] options;
uint256 startTime;
uint256 endTime;
uint256 minTokensToVote; // minimum holding to participate
bool resultsPublic; // public or hidden until end
}
struct VoteResult {
mapping(uint256 => uint256) voteCounts; // option index => token weight
mapping(address => bool) hasVoted;
mapping(address => uint256) votedOption;
}
mapping(uint256 => Vote) public votes;
mapping(uint256 => VoteResult) internal results;
IFanToken public fanToken;
function castVote(uint256 voteId, uint256 optionIndex) external {
Vote storage v = votes[voteId];
VoteResult storage r = results[voteId];
require(block.timestamp >= v.startTime && block.timestamp <= v.endTime);
require(!r.hasVoted[msg.sender], "Already voted");
uint256 balance = fanToken.balanceOf(msg.sender);
require(balance >= v.minTokensToVote, "Insufficient tokens");
// Vote weight = number of tokens
r.voteCounts[optionIndex] += balance;
r.hasVoted[msg.sender] = true;
r.votedOption[msg.sender] = optionIndex;
emit Voted(msg.sender, voteId, optionIndex, balance);
}
}
Examples of votes clubs actually conduct: stadium music selection, limited edition uniform design, charity organization selection for donation, captain question.
Exclusive NFT drops for holders
contract FanExclusiveNFT is ERC721, ERC2981 {
IFanToken public immutable fanToken;
uint256 public minTokensRequired;
uint256 public mintPrice;
mapping(address => bool) public hasMinted;
function mintExclusive(uint256 tokenId) external payable {
require(fanToken.balanceOf(msg.sender) >= minTokensRequired, "Not enough fan tokens");
require(!hasMinted[msg.sender], "Already minted");
require(msg.value >= mintPrice, "Insufficient payment");
hasMinted[msg.sender] = true;
_safeMint(msg.sender, tokenId);
// Royalties via ERC-2981
_setTokenRoyalty(tokenId, clubTreasury, 500); // 5%
}
}
Secondary Market with Managed Liquidity
Fan tokens shouldn't trade like DeFi tokens with permissionless liquidity — the club wants to control price volatility. Solution: own AMM with parameters.
contract FanTokenAMM {
// Modified xy=k formula with price bounds
uint256 public minPrice; // club sets floor
uint256 public maxPrice; // club sets ceiling (optional)
uint256 public tokenReserve;
uint256 public ethReserve;
function swap(uint256 tokenAmount, bool isBuy) external payable nonReentrant {
uint256 newPrice = _calculateNewPrice(tokenAmount, isBuy);
// Price floor: club can buy tokens below minPrice
if (!isBuy && newPrice < minPrice) {
revert PriceBelowFloor(newPrice, minPrice);
}
_executeSwap(tokenAmount, isBuy);
}
// Club adds liquidity from revenue
function addClubLiquidity() external payable onlyClub {
tokenReserve += _calculateTokensForETH(msg.value);
ethReserve += msg.value;
}
}
Price floor protects holders from sharp devaluation and builds token trust. Club finances buyback from ticket sales, merchandise, sponsorship revenues.
Club Administrative Panel
Club should manage token ecosystem without technical knowledge:
- Dashboard: current price, holders, trading volume, voting activity
- Voting: create question → set time → publish results
- NFT drops: upload art, set conditions, launch mint
- Buyback: add funds to liquidity pool with one click
- Analytics: holder demographics, purchase patterns, engagement score by fan
Regulatory Considerations
Fan tokens in some jurisdictions may qualify as securities. Key design questions:
- Utility-only: token grants no rights to club income, dividends, or equity. Only non-financial utility.
- No investment advertising: marketing built on fan engagement, not investment potential
- KYC/AML: mandatory for fiat on-ramp. For crypto-native purchases — by jurisdiction requirement
- Geo-restrictions: US, some cases EU (MiCA compliance) require special approach
Stack and Timeline
| Component | Technology | Timeline |
|---|---|---|
| Smart contracts | Solidity + Foundry | 4–5 weeks |
| MPC wallet + social login | Privy / Dynamic SDK | 2–3 weeks |
| Fiat on-ramp | Transak / MoonPay | 1–2 weeks |
| Backend API | Node.js + PostgreSQL | 3–4 weeks |
| Frontend (mobile-first) | React Native / Next.js | 4–6 weeks |
| Club admin panel | React + shadcn/ui | 2–3 weeks |
| Contract audit | 3–4 weeks |
Full development cycle: 19–27 weeks. Half the work is UX for non-crypto audience, which will never forgive "gas fee exceeded".







