Разработка launchpad для fan-токенов
Fan-токены — это не utility-токены в классическом смысле и не governance в DeFi-понимании. Это инструмент monetization болельщицкой аудитории, которая в 99% случаев не является crypto-native. Клуб хочет монетизировать лояльность, болельщик хочет ощущение причастности и эксклюзивных привилегий, платформа берёт комиссию. Launchpad для fan-токенов должен обслуживать именно эту модель — не permissionless DeFi, а managed onboarding для массовой аудитории.
Специфика fan-token launchpad vs классический IDO launchpad
Классический IDO launchpad работает с crypto-native аудиторией: MetaMask, USDT, понимание gas fees, risk tolerance. Fan-token launchpad работает с болельщиком, который пришёл из мобильного приложения клуба и, возможно, впервые слышит слово «кошелёк».
Ключевые отличия:
| Параметр | IDO Launchpad | Fan Token Launchpad |
|---|---|---|
| Аудитория | Crypto-native | Mainstream / спортивные болельщики |
| Onboarding | MetaMask + USDT | Email / социальные сети, fiat on-ramp |
| Токен utility | Governance, yield | Голосование за клуб, эксклюзивный контент |
| Ценообразование | Market-driven | Управляемое клубом, bonding curve |
| Regulatory | DeFi grey area | Ближе к ценным бумагам в ряде юрисдикций |
| Вторичный рынок | DEX | Управляемый AMM с liquidity контролем |
Архитектура токена и bonding curve
Fan-токен mechanics
Fan-токен Chiliz-style (FC Barcelona BAR, Juventus JUV) строится на нескольких принципах:
- Ограниченная эмиссия: фиксированный supply, контролируемый клубом
- Утилити-привязка: голосования, доступ к контенту, NFT drops, встречи с игроками
- Managed liquidity: клуб или платформа контролирует ликвидность, нет permissionless AMM
- Fiat gateway: покупка за фиат через карту или локальные платёжные методы
Bonding curve для primary sale
Вместо фиксированной цены или Dutch auction для fan-токенов часто применяется bonding curve — цена растёт по мере продаж. Это создаёт FOMO и награждает ранних покупателей.
contract FanTokenBondingCurve {
IERC20 public immutable fanToken;
uint256 public immutable initialPrice; // цена первого токена в USD (scaled 1e6)
uint256 public immutable slope; // крутизна кривой (scaled 1e18)
uint256 public tokensSold;
// Линейная bonding curve: price = initialPrice + slope * supply
function getCurrentPrice() public view returns (uint256) {
return initialPrice + (slope * tokensSold / 1e18);
}
// Стоимость покупки amount токенов начиная с текущего supply
function getBuyCost(uint256 amount) public view returns (uint256) {
// Интеграл линейной функции: сумма площади трапеции
uint256 priceAtStart = getCurrentPrice();
uint256 priceAtEnd = initialPrice + (slope * (tokensSold + amount) / 1e18);
return (priceAtStart + priceAtEnd) * amount / 2 / 1e6; // в базовой валюте
}
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);
// Возврат излишка
if (msg.value > cost) {
payable(msg.sender).transfer(msg.value - cost);
}
emit TokensPurchased(msg.sender, tokenAmount, cost);
}
}
Параметры initialPrice и slope настраиваются для каждого клуба. Типичный диапазон начальной цены — $1–5, финальная цена при полном размещении — $5–20.
Фиатный onboarding
Это ключевое отличие fan-token launchpad от DeFi платформы. Болельщик не должен знать про gas, он должен нажать «Купить» и заплатить картой.
Custody и custodial wallet
Два подхода к управлению кошельками пользователей:
Fully custodial (Chiliz подход): платформа держит приватные ключи. Пользователь видит баланс токенов, но не имеет on-chain кошелька. Максимальная простота UX, минимальные требования к пользователю. Минус: централизация, платформа должна соблюдать custody regulations.
MPC wallet (рекомендуемый подход): Multi-Party Computation кошелёк. Приватный ключ разделён между пользователем (через его устройство/аккаунт) и платформой. Ни одна сторона не имеет полного ключа. Пользователь подписывает транзакции через SDK, не видя raw private key. Платформа не имеет полного ключа — не несёт custody риска.
Провайдеры MPC wallet-as-a-service: Privy, Dynamic, Web3Auth, Capsule. Все поддерживают social login (Google, Apple, email).
// Privy integration — создание embedded wallet через 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 → автоматически создаёт embedded wallet
return;
}
const provider = await embeddedWallet!.getEthereumProvider();
const walletClient = createWalletClient({
account: embeddedWallet!.address as `0x${string}`,
transport: custom(provider)
});
// Пользователь подписывает транзакцию через UI Privy — не видит 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 ? 'Купить 10 токенов' : 'Войти и купить'}
</button>
);
}
Fiat-to-crypto конвертация
Пользователь платит фиатом — платформа конвертирует в crypto и выполняет транзакцию. Варианты:
On-ramp провайдеры: Stripe Crypto (через Link), MoonPay, Transak, Ramp Network. Интегрируются через виджет или API. Обрабатывают KYC/AML, поддерживают карты, банковские переводы, Apple Pay.
// Transak integration для on-ramp
function initiateFiatPurchase(fanTokenAmount: number, userAddress: string) {
const transak = new Transak({
apiKey: process.env.TRANSAK_API_KEY,
environment: 'PRODUCTION',
defaultCryptoCurrency: 'ETH',
walletAddress: userAddress,
// Кастомизация под клуб
themeColor: '009900', // цвет клуба
hostURL: window.location.origin,
widgetHeight: '570px',
widgetWidth: '450px',
// Webhook для отслеживания статуса
webhookStatusUrl: `${API_BASE}/transak-webhook`,
});
transak.init();
// После успешного on-ramp — автоматически вызываем purchase
transak.on(Transak.EVENTS.TRANSAK_ORDER_SUCCESSFUL, async (orderData) => {
await purchaseFanTokens(fanTokenAmount, userAddress, orderData.status.id);
});
}
Utility и engagement механики
Сам по себе токен без utility не имеет смысла. Launchpad должен включать инфраструктуру для утилити.
Голосования для клуба
contract FanVoting {
struct Vote {
string question;
string[] options;
uint256 startTime;
uint256 endTime;
uint256 minTokensToVote; // минимальный холдинг для участия
bool resultsPublic; // публичные или скрытые до окончания
}
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 = количество токенов
r.voteCounts[optionIndex] += balance;
r.hasVoted[msg.sender] = true;
r.votedOption[msg.sender] = optionIndex;
emit Voted(msg.sender, voteId, optionIndex, balance);
}
}
Примеры голосований, которые клубы реально проводят: выбор музыки на стадионе, дизайн лимитированной формы, выбор благотворительной организации для пожертвования, вопрос к капитану команды.
Exclusive NFT drops для холдеров
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 через ERC-2981
_setTokenRoyalty(tokenId, clubTreasury, 500); // 5%
}
}
Вторичный рынок с managed liquidity
Fan-токены не должны торговаться как DeFi токены с permissionless ликвидностью — клуб хочет контролировать price volatility. Решение: собственный AMM с параметрами.
contract FanTokenAMM {
// Модифицированная xy=k формула с price bounds
uint256 public minPrice; // клуб устанавливает floor
uint256 public maxPrice; // клуб устанавливает ceiling (опционально)
uint256 public tokenReserve;
uint256 public ethReserve;
function swap(uint256 tokenAmount, bool isBuy) external payable nonReentrant {
uint256 newPrice = _calculateNewPrice(tokenAmount, isBuy);
// Price floor: клуб может выкупать токены ниже minPrice
if (!isBuy && newPrice < minPrice) {
revert PriceBelowFloor(newPrice, minPrice);
}
_executeSwap(tokenAmount, isBuy);
}
// Клуб добавляет ликвидность из revenue
function addClubLiquidity() external payable onlyClub {
tokenReserve += _calculateTokensForETH(msg.value);
ethReserve += msg.value;
}
}
Price floor защищает холдеров от резкого обесценивания и создаёт доверие к токену. Клуб финансирует buyback из доходов от билетов, мерчандайза, sponsorship.
Административная панель клуба
Клуб должен управлять экосистемой токена без технических знаний:
- Dashboard: текущая цена, holders, trading volume, voting активность
- Голосования: создать вопрос → установить время → опубликовать результаты
- NFT drops: загрузить арт, установить условия, запустить mint
- Buyback: добавить средства в liquidity pool одной кнопкой
- Аналитика: демография холдеров, паттерны покупок, engagement score по болельщикам
Регуляторные соображения
Fan-токены в ряде юрисдикций могут квалифицироваться как securities. Ключевые вопросы при дизайне:
- Utility-only: токен не даёт права на доход клуба, дивиденды или equity. Только non-financial utility.
- No investment advertising: маркетинг строится на fan engagement, не на инвестиционном потенциале
- KYC/AML: обязателен для fiat on-ramp. Для crypto-native покупок — по требованию юрисдикции
- Geo-restrictions: США, в ряде случаев ЕС (MiCA compliance) требуют специального подхода
Стек и сроки
| Компонент | Технология | Срок |
|---|---|---|
| Smart contracts | Solidity + Foundry | 4–5 нед |
| MPC wallet + social login | Privy / Dynamic SDK | 2–3 нед |
| Fiat on-ramp | Transak / MoonPay | 1–2 нед |
| Backend API | Node.js + PostgreSQL | 3–4 нед |
| Frontend (mobile-first) | React Native / Next.js | 4–6 нед |
| Club admin panel | React + shadcn/ui | 2–3 нед |
| Аудит контрактов | 3–4 нед |
Полный цикл разработки: 19–27 недель. Половина работы — UX для non-crypto аудитории, которая никогда не простит "gas fee exceeded".







