Разработка платформы крипто-краудфандинга
Принципиальная разница между крипто-краудфандингом и ICO: в краудфандинге бэкеры финансируют конкретный продукт или проект, а не покупают спекулятивный токен. Kickstarter модель — создатель обещает что-то сделать, получает деньги заранее. В крипто версии smart contract удерживает средства в escrow и освобождает их по мере выполнения milestones — это убирает центрального посредника-платёжного оператора и делает возврат средств автоматическим при недостижении цели.
Ключевые отличия от классического ICO контракта
Краудфандинг имеет специфическую механику, которой нет в простом token sale:
Milestone-based funding — средства не переходят к создателю сразу. После достижения каждой вехи (milestone) часть средств разблокируется. Бэкеры могут голосовать за отказ от выплаты если milestone не выполнен.
Rewards вместо токенов — типичная reward-based кампания (Kickstarter модель): бэкер получает физический или цифровой продукт, не финансовый инструмент. Это избегает регулирования как securities.
Refund при недостижении softcap — обязательный механизм. Без него это не краудфандинг, а предоплата с высоким риском для покупателя.
Creator accountability — в отличие от ICO где команда получает деньги и исчезает, краудфандинг включает механизмы accountability: milestone верификацию, возможность vote to refund при недобросовестном поведении.
Смарт-контракт: Campaign и Escrow
contract CrowdfundingCampaign {
enum Status { Active, Successful, Failed, Cancelled }
struct Milestone {
string description;
uint256 fundsToRelease; // часть средств при достижении
uint256 deadline;
bool isCompleted;
bool isFailed;
uint256 approvalVotes; // бэкеры голосуют за подтверждение
uint256 rejectionVotes;
mapping(address => bool) hasVoted;
}
address public creator;
uint256 public softcap;
uint256 public hardcap;
uint256 public deadline;
uint256 public totalRaised;
Status public status;
Milestone[] public milestones;
mapping(address => uint256) public contributions;
IERC20 public paymentToken; // USDC/USDT для стабильной суммы
function contribute(uint256 amount) external {
require(status == Status.Active, "Campaign not active");
require(block.timestamp < deadline, "Campaign ended");
require(totalRaised + amount <= hardcap, "Hardcap reached");
paymentToken.transferFrom(msg.sender, address(this), amount);
contributions[msg.sender] += amount;
totalRaised += amount;
// Если hardcap достигнут — завершаем кампанию
if (totalRaised >= hardcap) {
status = Status.Successful;
}
emit ContributionReceived(msg.sender, amount, totalRaised);
}
function finalizeCampaign() external {
require(block.timestamp >= deadline, "Deadline not reached");
require(status == Status.Active, "Already finalized");
if (totalRaised >= softcap) {
status = Status.Successful;
// Первый milestone начинает тикать
milestones[0].deadline = block.timestamp + milestones[0].duration;
emit CampaignSuccessful(totalRaised);
} else {
status = Status.Failed;
emit CampaignFailed(totalRaised, softcap);
}
}
// Только при Failed status
function claimRefund() external {
require(status == Status.Failed || status == Status.Cancelled, "Not refundable");
uint256 amount = contributions[msg.sender];
require(amount > 0, "Nothing to refund");
contributions[msg.sender] = 0;
paymentToken.transfer(msg.sender, amount);
emit RefundClaimed(msg.sender, amount);
}
}
Milestone governance: бэкеры как контролёры
function approveMilestone(uint256 milestoneIndex) external {
require(contributions[msg.sender] > 0, "Not a backer");
Milestone storage milestone = milestones[milestoneIndex];
require(!milestone.hasVoted[msg.sender], "Already voted");
require(!milestone.isCompleted && !milestone.isFailed, "Already resolved");
milestone.hasVoted[msg.sender] = true;
// Вес голоса пропорционален вкладу
milestone.approvalVotes += contributions[msg.sender];
_checkMilestoneResolution(milestoneIndex);
}
function rejectMilestone(uint256 milestoneIndex) external {
require(contributions[msg.sender] > 0, "Not a backer");
Milestone storage milestone = milestones[milestoneIndex];
require(!milestone.hasVoted[msg.sender], "Already voted");
milestone.hasVoted[msg.sender] = true;
milestone.rejectionVotes += contributions[msg.sender];
_checkMilestoneResolution(milestoneIndex);
}
function _checkMilestoneResolution(uint256 index) internal {
Milestone storage milestone = milestones[index];
uint256 APPROVAL_THRESHOLD = 5000; // 50% от totalRaised
uint256 REJECTION_THRESHOLD = 3300; // 33% достаточно для reject
if (milestone.approvalVotes * 10000 / totalRaised >= APPROVAL_THRESHOLD) {
milestone.isCompleted = true;
// Переводим средства создателю
paymentToken.transfer(creator, milestone.fundsToRelease);
emit MilestoneApproved(index, milestone.fundsToRelease);
} else if (milestone.rejectionVotes * 10000 / totalRaised >= REJECTION_THRESHOLD) {
milestone.isFailed = true;
// Оставшиеся средства идут на рефанд
status = Status.Cancelled;
emit MilestoneRejected(index);
}
}
Важный нюанс по голосованию: порог одобрения vs отклонения асимметричен. Для одобрения нужно большинство (50%+), для отклонения — меньший порог (33%). Это защита от того, что создатель привлечёт своих людей для голосования за себя.
NFT как reward tier
Крипто-краудфандинг часто комбинирует с NFT: каждый tier взноса — уникальный NFT:
contract CampaignRewards is ERC721 {
struct RewardTier {
uint256 minContribution;
uint256 maxSupply;
uint256 minted;
string metadataURI; // IPFS URI с описанием reward
}
RewardTier[] public tiers;
mapping(address => uint256) public backerTier;
// Вызывается при contribution или после завершения кампании
function mintRewardNFT(address backer, uint256 contribution) internal {
// Определяем tier по размеру взноса
uint256 tierIndex = _getTierForAmount(contribution);
RewardTier storage tier = tiers[tierIndex];
require(tier.minted < tier.maxSupply, "Tier sold out");
uint256 tokenId = _nextTokenId++;
_safeMint(backer, tokenId);
_setTokenURI(tokenId, tier.metadataURI);
tier.minted++;
backerTier[backer] = tierIndex;
emit RewardNFTMinted(backer, tokenId, tierIndex);
}
}
NFT как receipt для бэкера — не просто косметика. Он является доказательством участия, может торговаться на вторичном рынке (если кампания популярна, early backer NFT ценятся), и может быть использован для дополнительных perks (Discord роли, early access, governance).
Мультивалютные взносы
Принимать только один токен — ограничение для пользователей. Реализация мультивалютного escrow через on-chain swap:
// Backend логика: пользователь хочет платить ETH, кампания принимает USDC
async function processContribution(
userWallet: string,
paymentToken: string, // "ETH" | "USDC" | "WBTC"
amount: bigint,
campaignId: string
): Promise<string> {
if (paymentToken === "USDC") {
// Прямой contribution
return await campaign.contribute(amount);
}
// Для non-USDC: swap через 1inch API, затем contribute
const swapData = await getOneInchSwapData({
fromToken: paymentToken,
toToken: USDC_ADDRESS,
amount,
slippage: 1, // 1%
receiver: campaign.address, // прямо на campaign контракт
});
// Атомарный swap + contribute через multicall
return await multicall([
{ to: swapData.to, data: swapData.data, value: swapData.value },
{ to: campaign.address, data: encodeContribute(convertedAmount) },
]);
}
Platform fee и модель монетизации
Платформа берёт процент от успешно профинансированных кампаний (стандарт Kickstarter — 5%). Это реализуется в момент milestone release:
uint256 public constant PLATFORM_FEE_BPS = 500; // 5%
address public platformTreasury;
function _releaseMilestoneFunds(uint256 milestoneIndex) internal {
uint256 gross = milestones[milestoneIndex].fundsToRelease;
uint256 fee = (gross * PLATFORM_FEE_BPS) / 10000;
uint256 net = gross - fee;
paymentToken.transfer(platformTreasury, fee);
paymentToken.transfer(creator, net);
}
Дополнительные источники дохода платформы: listing fee (фиксированная плата за создание кампании), premium features (расширенная аналитика, featured placement), launchpad синергия (успешные краудфандинг проекты могут получить IDO слот).
Антимошеннические механизмы
Creator verification — KYC для создателей кампаний обязателен. Аnononymous creator + $1M в escrow = очевидный rug pull вектор.
Milestone escrow — ни один доллар не идёт создателю до выполнения первого milestone. Классический "fundraise and disappear" невозможен.
Emergency stop — платформа может остановить кампанию при подтверждённом мошенничестве, вернуть средства бэкерам. Это centralized override, но необходимый.
Social proof requirements — верификация команды через LinkedIn/GitHub, публичный roadmap в IPFS (immutable commitment), предварительный продукт или MVP демо.
Базовая платформа с двумя ролями (creator, backer), milestone voting и NFT rewards: 10–14 недель разработки.







