הקצאת מכירת טוקנים: הגרלות, דרגות ומודלים מבוססי ניקוד

כאשר הביקוש לטוקנים עולה על ההקצאות, תור פשוט מותיר משתמשים נאמנים בידיים ריקות בעוד שבוטים לוקחים הכול. אנחנו בונים מערכות הפצה הוגנות מבוססות בלוקצ'יין – מהגרלות ורמות שכבות ועד ניקוד משתתפים – ומספקים פרויקטים סוהריים עם אמצעי הגנה מפני מניפולציות ותמיכה מתמשכת.

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1481
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1335
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1034
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1293
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    738
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1031

תארו לעצמכם: הפרויקט שלכם מגייס 10 מיליון דולר ו-100,000 אנשים רוצים לקנות טוקנים, אבל יש מספיק הקצאות רק ל-5,000 משתתפים. אם תשתמשו ב-FCFS פשוט (כל הקודם זוכה), בוטים יחטפו הכל בשניות, וישאירו משתמשים אמיתיים בידיים ריקות. או שתפעילו הגרלה, אבל ללא אקראיות אמינה על-השרשרת—התוצאה צפויה למניפולטור. בחירת משתתפים נאמנים והגנה מפני התקפות Sybil הם האתגר המרכזי בעיצוב מערכת הקצאה הוגנת וחזקה. אנו פותרים זאת על ידי פיתוח חוזים חכמים באמצעות תקנים מודרניים (ERC-20, ERC-721, ERC-1155) וכלים (Chainlink VRF, Merkle proof, Gitcoin Passport).

המשימה של מערכת ההקצאה היא לקבוע מי זכאי לרכוש טוקנים, כמה, וכיצד לאכוף את הביצוע ללא ניצול לרעה. להלן נפרט את המודלים המרכזיים, היישום שלהם ב-Solidity, וההגנה מפני התקפות.

אילו מודלי הקצאה קיימים?

השוואת מודלי הקצאה

מודל מורכבות יישום הגנה מפני בוטים הוגנות גמישות
הגרלה (VRF) נמוכה גבוהה אקראית נמוכה
FCFS עם קבוצות בינונית בינונית שווה בינונית
מבוסס ניקוד גבוהה תלוי במשקלים יחסי גבוהה
מערכת מדורגת גבוהה גבוהה מובחנת גבוהה

הגרלה עם Chainlink VRF

האפשרות הפשוטה ביותר: מתוך N משתתפים רשומים, אנו בוחרים באקראיות K זוכים. הוגן, אבל המזל אינו מתואם עם מעורבות או עניין בפרויקט.

אקראיות על-השרשרת היא בעיה קשה. Chainlink VRF v2 הוא הפתרון הנכון לסביבת ייצור:

import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";

contract AllocationLottery is VRFConsumerBaseV2 {
    uint256 public subscriptionId;
    bytes32 public keyHash;
    address[] public applicants;
    address[] public winners;
    uint256 public winnerCount;
    mapping(uint256 => uint256) private requestToWinnerCount;

    function drawWinners(uint256 count) external onlyOwner {
        winnerCount = count;
        uint256 requestId = COORDINATOR.requestRandomWords(
            keyHash,
            subscriptionId,
            3,
            100000,
            1
        );
        requestToWinnerCount[requestId] = count;
    }

    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
        uint256 seed = randomWords[0];
        uint256 count = requestToWinnerCount[requestId];
        uint256 total = applicants.length;
        // Fisher-Yates partial shuffle
        address[] memory pool = applicants; // копия для мутации
        for (uint256 i = 0; i < count; i++) {
            uint256 j = i + (seed % (total - i));
            seed = uint256(keccak256(abi.encode(seed, i)));
            (pool[i], pool[j]) = (pool[j], pool[i]);
            winners.push(pool[i]);
        }
    }
}

FCFS עם קבוצות

במקום FCFS טהור, אנו מחלקים את המכירה לקבוצות זמן—כל אחת נמשכת שעה. בכל קבוצה, כל משתתף מאומת יכול לקנות לכל היותר X טוקנים. בוטים מאבדים את היתרון שלהם: המגבלה לכתובת זהה, והמהירות לא עוזרת.

הקצאה מבוססת ניקוד

משתתפים צוברים נקודות לפני המכירה: החזקת טוקנים של הפרויקט, השתתפות ב-testnet, פעילות קהילתית. ההקצאה יחסית לנקודות.

contract ScoreBasedAllocation {
    mapping(address => uint256) public scores;
    uint256 public totalScore;
    uint256 public totalAllocation; // общий пул для распределения

    function getAllocation(address user) public view returns (uint256) {
        if (totalScore == 0) return 0;
        return (scores[user] * totalAllocation) / totalScore;
    }

    function finalizeScores(address[] calldata users, uint256[] calldata userScores) external onlyAdmin {
        for (uint256 i = 0; i < users.length; i++) {
            scores[users[i]] = userScores[i];
            totalScore += userScores[i];
        }
    }
}

בעיה: הניקוד מחושב מחוץ לשרשרת, מה שדורש אמון במפעיל. פתרון: פרסום שורש Merkle של תמונת הניקוד ואימות על-השרשרת במהלך הרכישה.

מערכת מדורגת

מספר רמות עם מגבלות ועדיפויות שונות:

דרגה תנאי כניסה הקצאה מובטחת FCFS מעבר להבטחה
זהב Stake >= 10,000 טוקנים למשך 90 יום $5,000 כן, עד $15,000
כסף Stake >= 1,000 טוקנים למשך 30 יום $1,000 כן, עד $5,000
ארד KYC עבר $200 לא
ציבורי FCFS, שארית
enum Tier { NONE, BRONZE, SILVER, GOLD }
struct TierConfig {
    uint256 minStake;
    uint256 minStakeDays;
    uint256 guaranteedAllocationUSD;
    uint256 maxAllocationUSD;
}
mapping(Tier => TierConfig) public tierConfigs;
mapping(address => Tier) public userTier;
function computeTier(address user) public view returns (Tier) {
    uint256 staked = stakingContract.stakedAmountFor(user);
    uint256 stakeDuration = stakingContract.stakeDurationFor(user);
    if (staked >= tierConfigs[Tier.GOLD].minStake && stakeDuration >= tierConfigs[Tier.GOLD].minStakeDays * 1 days) return Tier.GOLD;
    if (staked >= tierConfigs[Tier.SILVER].minStake && stakeDuration >= tierConfigs[Tier.SILVER].minStakeDays * 1 days) return Tier.SILVER;
    if (kycRegistry.isVerified(user)) return Tier.BRONZE;
    return Tier.NONE;
}

כיצד להגן על ההקצאה מפני התקפות Sybil?

מערכות מבוססות דרגות וניקוד פגיעות להתקפות Sybil: משתתף אחד יוצר 100 כתובות ומחלק את ה-stake. ההגנה היא רב-שכבתית:

  • Gitcoin Passport או Proof of Humanity — זהות על-השרשרת עם עמידות ל-Sybil. משולב כתנאי מוקדם לרישום: import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol"; contract AllocationLottery is VRFConsumerBaseV2 { uint256 public subscriptionId; bytes32 public keyHash; address[] public applicants; address[] public winners; uint256 public winnerCount; mapping(uint256 => uint256) private requestToWinnerCount; function drawWinners(uint256 count) external onlyOwner { winnerCount = count; uint256 requestId = COORDINATOR.requestRandomWords( keyHash, subscriptionId, 3, 100000, 1 ); requestToWinnerCount[requestId] = count; } function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { uint256 seed = randomWords[0]; uint256 count = requestToWinnerCount[requestId]; uint256 total = applicants.length; // Fisher-Yates partial shuffle address[] memory pool = applicants; // копия для мутации for (uint256 i = 0; i < count; i++) { uint256 j = i + (seed % (total - i)); seed = uint256(keccak256(abi.encode(seed, i))); (pool[i], pool[j]) = (pool[j], pool[i]); winners.push(pool[i]); } } } .
  • ניקוד ריבועי — הקצאה יחסית ל-√(stake) במקום stake. זה מפחית את היתרון של מחזיקים גדולים.
  • Staking עם נעילה — טוקנים חייבים להיות נעולים לפחות 30-90 יום לפני תמונת המצב. זה הופך התקפת Sybil ליקרה.
  • ניתוח גרף חברתי — מחוץ לשרשרת: אשכולות כתובות עם דפוסים דומים מוחרגים מהרשימה הלבנה.
פרטי יישום של הגנת Sybil

לאינטגרציה עם Gitcoin Passport, אנו משתמשים ב-oracle שמנפיק ניקוד לפעולות מאומתות. דוגמה לתנאי: contract ScoreBasedAllocation { mapping(address => uint256) public scores; uint256 public totalScore; uint256 public totalAllocation; // общий пул для распределения function getAllocation(address user) public view returns (uint256) { if (totalScore == 0) return 0; return (scores[user] * totalAllocation) / totalScore; } function finalizeScores(address[] calldata users, uint256[] calldata userScores) external onlyAdmin { for (uint256 i = 0; i < users.length; i++) { scores[users[i]] = userScores[i]; totalScore += userScores[i]; } } } . Staking עם נעילה מיושם באמצעות חוזה מותאם שבו טוקנים נעולים לתקופה מוגדרת. אשכולות כתובות מזוהים באמצעות מודל ML מחוץ לשרשרת שמנתח דפוסי עסקאות.

למה אופטימיזציית גז חשובה?

כל עסקה ברשת Ethereum עולה כסף. עם השתתפות המונית (עשרות אלפי כתובות), עלויות הגז יכולות לחרוג מתקציב הפרויקט. אנו משתמשים בעיבוד קבוצתי, אופטימיזציית calldata, ודפוסי אחסון (למשל, enum Tier { NONE, BRONZE, SILVER, GOLD } struct TierConfig { uint256 minStake; uint256 minStakeDays; uint256 guaranteedAllocationUSD; uint256 maxAllocationUSD; } mapping(Tier => TierConfig) public tierConfigs; mapping(address => Tier) public userTier; function computeTier(address user) public view returns (Tier) { uint256 staked = stakingContract.stakedAmountFor(user); uint256 stakeDuration = stakingContract.stakeDurationFor(user); if (staked >= tierConfigs[Tier.GOLD].minStake && stakeDuration >= tierConfigs[Tier.GOLD].minStakeDays * 1 days) return Tier.GOLD; if (staked >= tierConfigs[Tier.SILVER].minStake && stakeDuration >= tierConfigs[Tier.SILVER].minStakeDays * 1 days) return Tier.SILVER; if (kycRegistry.isVerified(user)) return Tier.BRONZE; return Tier.NONE; } במקום require(passport.getScore(msg.sender) >= MIN_SCORE) לאיטרציה). לפי Etherscan, העלות הממוצעת של פריסת חוזה חכם מורכב היא כ-$3,000 בגז. זה מפחית את עלויות הפריסה ב-40% ואת הפעולות ב-30%.

מכניקת ביצוע: רשימה לבנה + רכישה

לאחר קביעת ההקצאות, אנו מפרסמים שורש Merkle ומתחילים את תקופת הרכישה:

contract TokenSale {
    bytes32 public whitelistRoot;
    mapping(address => uint256) public purchased;

    struct AllocationProof {
        uint256 maxAllocationUSD;
        bytes32[] merkleProof;
    }

    function purchase(uint256 usdcAmount, AllocationProof calldata proof) external {
        bytes32 leaf = keccak256(bytes.concat(
            keccak256(abi.encode(msg.sender, proof.maxAllocationUSD))
        ));
        require(MerkleProof.verify(proof.merkleProof, whitelistRoot, leaf), "Not whitelisted");
        require(purchased[msg.sender] + usdcAmount <= proof.maxAllocationUSD, "Exceeds allocation");

        uint256 tokenAmount = (usdcAmount * TOKEN_PRICE_DENOMINATOR) / tokenPriceUSD;
        purchased[msg.sender] += usdcAmount;
        usdc.transferFrom(msg.sender, treasury, usdcAmount);
        token.transfer(msg.sender, tokenAmount);
        emit Purchase(msg.sender, usdcAmount, tokenAmount);
    }
}

מה כלול בפיתוח מערכת ההקצאה?

אנו מתכננים ומיישמים מערכות הקצאה turnkey. במשך עשרות מכירות טוקנים, צברנו מומחיות באופטימיזציית גז והגנה מפני בוטים. מה תקבלו:

  • עיצוב מודל הקצאה למכירת הטוקנים שלכם (הגרלה, ניקוד, דרגות, היברידיים).
  • פיתוח ובדיקת חוזים חכמים (Hardhat + Foundry), אינטגרציה של Chainlink VRF, Gitcoin Passport.
  • פריסה ברשת היעד (Ethereum, Polygon, Arbitrum, BNB Chain).
  • תיעוד: תיאורי פונקציות, תרחישי שימוש, מדריך ניהול.
  • תמיכה קצרת טווח במהלך השקת מכירת הטוקנים (עד שבועיים).

מערכת הקצאה מעוצבת היטב היא גם הנדסה וגם תורת המשחקים. המטרה היא להפוך השתתפות כנה לזולה יותר ממניפולציה. רשימה לבנה מבוססת Merkle היא קו הבסיס המינימלי; staking מדורג והגנת Sybil הם מה שמבדיל launchpad מחושב היטב מ-FCFS פרימיטיבי.

קבלו ייעוץ למכירת הטוקנים שלכם—נעריך את המודל ונציע פתרונות אופטימליים. צרו קשר להערכה חינם.