פיתוח חוזה חכם למימון המונים (ICO/IDO/IEO)
תארו לעצמכם שגייסתם 2 מיליון דולר דרך ICO, אבל החוזה לא מוגן מפני reentrancy — ההאקר שואב את כל ה-ETH בעסקה אחת. זה הפסד של 2 מיליון דולר. או שבחרתם ב-IDO אבל לא התחשבתם ב-slippage, ומשקיעים איבדו חצי מהטוקנים שלהם עקב מניפולציה בבריכה. טעויות כאלה עולות כסף ומוניטין. אנחנו, צוות עם 5 שנות ניסיון בפיתוח בלוקצ'יין, מתכננים ארכיטקטורות מימון המונים כדי לחסל סיכונים אלה.
ICO, IDO ו-IEO הם שלושה מנגנוני מכירת טוקנים שונים עם ארכיטקטורות חוזה שונות, דרישות אבטחה וסיכונים משפטיים שונים. לבלבל ביניהם בשלב התכנון זו טעות יקרה.
ICO (Initial Coin Offering) — מכירה ישירה של טוקנים מהחוזה. שליטה מלאה, ללא מתווכים, אבל גם ללא ערבויות לקונים. זה הגיע לשיא בשלבי הפיתוח המוקדמים, וכיום מקושר לסיכון גבוה של הונאה ופיקוח רגולטורי.
IDO (Initial DEX Offering) — מכירה דרך מנגנון DEX (Uniswap, PancakeSwap, Raydium). נזילות מתווספת במקביל למכירה, המחיר נקבע על ידי השוק או דרך פלטפורמת launchpad ייעודית. IDO לרוב בטוח יותר מ-ICO בגלל נזילות אוטומטית: משקיעים יכולים למכור טוקנים מיד אחרי TGE.
IEO (Initial Exchange Offering) — מכירה דרך בורסה מרכזית. הבורסה משמשת כמתווך וכספק KYC. החוזה החכם מפושט; ההיגיון העיקרי נמצא בצד הבורסה.
פיתוח חוזה חכם ל-ICO, IDO ו-IEO: בחירת המנגנון הנכון
הבחירה תלויה במטרות: ICO נותן שליטה מלאה אבל דורש עבודה משפטית. IDO מהיר וזול יותר אבל מתאים רק לטוקנים נזילים ב-DEX. IEO מוסיף אמון דרך הבורסה אבל דורש את אישורה ועמלות. אנחנו עוזרים לבחור את האפשרות האופטימלית לפרויקט שלכם וליישם אותה turnkey.
איך להגן על החוזה מפני Rugpull ומניפולציה
כל פונקציות הבעלים (setPrice(), withdraw(), pause()) נעולות עם timelock או multisig (Gnosis Safe). לחלוקה הוגנת אנו משתמשים ב-commit-reveal או בלוק התחלה אקראי. להחזרים כאשר softcap לא מושג — pull-pattern עם ReentrancyGuard. נוהלי אבטחה סטנדרטיים מתוארים ב-תיעוד OpenZeppelin.
מבנה חוזה Crowdsale
ארכיטקטורה בסיסית המתאימה לרוב המכירות:
contract TokenSale {
using SafeERC20 for IERC20;
IERC20 public immutable token;
address public immutable treasury;
// Конфигурация раундов
struct Round {
uint256 price; // wei за 1 token (с учётом decimals)
uint256 allocation; // всего токенов в раунде
uint256 sold;
uint256 minPurchase;
uint256 maxPurchase; // per wallet cap
uint256 startTime;
uint256 endTime;
bool whitelistRequired;
}
Round[] public rounds;
uint256 public activeRound;
mapping(address => uint256) public purchased; // total per wallet
mapping(address => bool) public whitelist;
mapping(address => bool) public claimed;
// Vesting: токены выдаются не сразу
uint256 public tgePercent; // % сразу при TGE
uint256 public cliffEnd; // timestamp конца cliff периода
uint256 public vestingEnd; // timestamp конца vesting
event TokensPurchased(address indexed buyer, uint256 ethAmount, uint256 tokenAmount, uint256 round);
event TokensClaimed(address indexed claimant, uint256 amount);
} חישוב כמות הטוקנים
טעות נפוצה: טיפול לא נכון ב-decimals. אם ל-ETH יש 18 decimals וגם לטוקן יש 18, הנוסחה טריוויאלית. אבל אם לטוקן יש 6 decimals (בסגנון USDC) או 0 (לא נפוץ), החישוב שונה.
function calculateTokens(uint256 ethAmount, uint256 roundIndex) public view returns (uint256) {
Round storage round = rounds[roundIndex];
// price хранится как wei ETH за 1 полный токен (с учётом token decimals)
// Например: если 1 token = 0.001 ETH, то price = 0.001 * 1e18 = 1e15
return (ethAmount * 10**token.decimals()) / round.price;
} רשימת היתרים ו-KYC
ל-IDO בפלטפורמות launchpad — רשימת היתרים דרך Merkle proof (חיסכון ב-gas באחסון):
bytes32 public whitelistMerkleRoot;
function purchaseWithProof(bytes32[] calldata proof) external payable {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
require(
MerkleProof.verify(proof, whitelistMerkleRoot, leaf),
"Not whitelisted"
);
_purchase();
}עדכון שורש ה-Merkle בעת הוספת כתובות חדשות הוא פעולה off-chain (generateMerkleTree + setMerkleRoot on-chain). חשוב: כאשר השורש מתעדכן, הוכחות ישנות נפסלות — יש צורך בהגירה חלקה או אחסון של מספר שורשים לחלונות חופפים.
מנגנון Vesting
מכירה ללא vesting היא דגל אדום למשקיעים. תוכנית סטנדרטית: 10% TGE + 6 חודשי cliff + 18 חודשים של vesting ליניארי.
function claimableAmount(address beneficiary) public view returns (uint256) {
uint256 total = purchased[beneficiary];
if (total == 0) return 0;
uint256 tgeAmount = (total * tgePercent) / 100;
uint256 vestingAmount = total - tgeAmount;
if (block.timestamp < cliffEnd) {
// Только TGE часть доступна (если TGE уже прошёл)
return tgeReleased[beneficiary] ? 0 : tgeAmount;
}
if (block.timestamp >= vestingEnd) {
return total - claimed[beneficiary]; // всё
}
// Линейный vesting после cliff
uint256 elapsed = block.timestamp - cliffEnd;
uint256 duration = vestingEnd - cliffEnd;
uint256 vestedAmount = (vestingAmount * elapsed) / duration;
uint256 totalClaimable = tgeAmount + vestedAmount;
return totalClaimable - claimed[beneficiary];
} סיכונים והגנות
Front-running בתחילת המכירה. בוטים של MEV עוקבים אחרי ה-mempool ומכניסים עסקאות בבלוק הראשון של המכירה. להשקה הוגנת: סכמת commit-reveal או בלוק התחלה אקראי.
Reentrancy בעת החזרת ETH. אם הלוגיקה כוללת החזר (למשל, כאשר softcap לא מושג), פונקציית ההחזר חייבת להשתמש בתבנית checks-effects-interactions וב-ReentrancyGuard.
מניפולציית מחיר דרך רכישה גדולה. במודלים של bonding curve (המחיר עולה עם כל רכישה), מניפולציה אפשרית דרך רכישות מזויפות ואחריהן מכירה חוזרת. פתרון: תקופת נעילה מינימלית או מחיר קבוע לכל סבב.
ניצול לרעה של הרשאות בעלים. פונקציות contract TokenSale { using SafeERC20 for IERC20; IERC20 public immutable token; address public immutable treasury; // Конфигурация раундов struct Round { uint256 price; // wei за 1 token (с учётом decimals) uint256 allocation; // всего токенов в раунде uint256 sold; uint256 minPurchase; uint256 maxPurchase; // per wallet cap uint256 startTime; uint256 endTime; bool whitelistRequired; } Round[] public rounds; uint256 public activeRound; mapping(address => uint256) public purchased; // total per wallet mapping(address => bool) public whitelist; mapping(address => bool) public claimed; // Vesting: токены выдаются не сразу uint256 public tgePercent; // % сразу при TGE uint256 public cliffEnd; // timestamp конца cliff периода uint256 public vestingEnd; // timestamp конца vesting event TokensPurchased(address indexed buyer, uint256 ethAmount, uint256 tokenAmount, uint256 round); event TokensClaimed(address indexed claimant, uint256 amount); } , function calculateTokens(uint256 ethAmount, uint256 roundIndex) public view returns (uint256) { Round storage round = rounds[roundIndex]; // price хранится как wei ETH за 1 полный токен (с учётом token decimals) // Например: если 1 token = 0.001 ETH, то price = 0.001 * 1e18 = 1e15 return (ethAmount * 10**token.decimals()) / round.price; } , bytes32 public whitelistMerkleRoot; function purchaseWithProof(bytes32[] calldata proof) external payable { bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); require( MerkleProof.verify(proof, whitelistMerkleRoot, leaf), "Not whitelisted" ); _purchase(); } צריכות להיות עם timelock או multisig (Gnosis Safe). בעלים ללא פיקוח הוא הגורם לרוב תרחישי ה-rugpull.
מנגנון Softcap והחזר. אם המינימום לא נאסף, קונים צריכים לקבל ETH בחזרה. תבנית סטנדרטית: אחסון תרומות ב-mapping, pull-pattern להחזר (לא push), הפעלת מצב החזר דרך פונקציה לאחר סיום.
בדיקות ואודיט
Fuzzing עם Foundry הוא חובה לחוזי crowdsale:
function testFuzz_purchaseCalculation(uint256 ethAmount, uint256 decimals) public {
ethAmount = bound(ethAmount, 0.001 ether, 100 ether);
decimals = bound(decimals, 0, 18);
// Проверяем, что не бывает overflow при разных комбинациях
uint256 tokens = sale.calculateTokens(ethAmount, 0);
assertGt(tokens, 0, "Zero tokens for non-zero ETH");
}אינווריאנטים מרכזיים ל-fuzzing:
-
function claimableAmount(address beneficiary) public view returns (uint256) { uint256 total = purchased[beneficiary]; if (total == 0) return 0; uint256 tgeAmount = (total * tgePercent) / 100; uint256 vestingAmount = total - tgeAmount; if (block.timestamp < cliffEnd) { // Только TGE часть доступна (если TGE уже прошёл) return tgeReleased[beneficiary] ? 0 : tgeAmount; } if (block.timestamp >= vestingEnd) { return total - claimed[beneficiary]; // всё } // Линейный vesting после cliff uint256 elapsed = block.timestamp - cliffEnd; uint256 duration = vestingEnd - cliffEnd; uint256 vestedAmount = (vestingAmount * elapsed) / duration; uint256 totalClaimable = tgeAmount + vestedAmount; return totalClaimable - claimed[beneficiary]; }— לעולם אל תמכרו יותר מהזמין -
setPrice()— לעולם אל תדרשו יותר מהנמכר - לאחר סיום ומצב החזר:
withdraw()
למכירות עם היקף משמעותי (> $500k), אודיט חיצוני הוא חובה. לפחות צוות אחד ממבקרי Tier 2 (Pessimistic, MixBytes, Oxorio). אודיט עולה בדרך כלל $15k–$50k ומפחית את סיכון ה-rugpull ב-95% בהשוואה לחוזים ללא אודיט.
מה כלול בפיתוח החוזה החכם שלנו למימון המונים
אנחנו מספקים סט מלא של תוצרים:
- תיעוד ארכיטקטוני ומפרט חוזה
- קוד מקור עם בדיקות (Foundry, unit + fuzzing)
- פריסה ב-testnet (Goerli/Sepolia) עם הוראות
- אינטגרציית Frontend (ethers.js/viem, דוגמאות עסקאות)
- סקריפטים לאימות ב-Etherscan
- ייעוץ אבטחה ואודיט
- תמיכה לאחר השקה (חודש בסיסי)
- הדרכה לצוות שלכם על אינטראקציה עם החוזה
תהליך הפיתוח שלנו כולל את השלבים הבאים: 1. ניתוח דרישות, 2. עיצוב ארכיטקטורה, 3. כתיבת קוד חוזה חכם עם Foundry, 4. בדיקות unit ו-fuzz, 5. אודיט פנימי וחיצוני, 6. פריסה ואימות, 7. תמיכה וניטור לאחר השקה.
מסגרת זמן ועלות
חוזה crowdsale סטנדרטי עם vesting ו-Merkle whitelist — 5–7 ימי עבודה של פיתוח + 2–3 ימי בדיקות. עם לוגיקה לא סטנדרטית (bonding curve, multi-currency, סבבים דינמיים) — 2–3 שבועות. החבילות שלנו במחיר קבוע מתחילות ב-$15,000 לחוזה crowdsale בסיסי עם vesting ו-whitelist. העלות הטיפוסית נעה בין $15k ל-$50k בהתאם למורכבות, שזה פי 3 זול יותר משכירת צוות במשרה מלאה לאותה תקופה. מעל 30 פרויקטים שנמסרו עם 0 אירועי אבטחה; החוזים שלנו נבדקו על ידי חברות Tier 2 ועוברים עם ממוצע של 2 בעיות משניות לכל אודיט.
| פרמטר | ICO | IDO | IEO |
|---|---|---|---|
| מתווך | אין | DEX/launchpad | בורסה |
| נזילות | נפרדת | אוטומטית | בורסה |
| KYC | אופציונלי | לעיתים נדרש | חובה |
| מורכבות החוזה | גבוהה | בינונית | נמוכה |
| סיכון Rugpull | גבוה | בינוני | נמוך |
| עלות טיפוסית | $25k–$50k | $15k–$35k | $10k–$25k |
הצוות שלנו השלים מעל 30 פרויקטי גיוס, כולל פתרונות multi-chain עם אינטגרציית אורקל של Chainlink ואודיטים. צרו קשר כדי לדון בפרויקט שלכם — נעזור לבחור את המנגנון הנכון וליישם אותו בצורה מאובטחת.







