העברת טוקנים אוטומטית עם מועד אחרון ושריפה

כאשר מחזיקים לא מעבירים את הנכסים שלהם לטוקן חדש, הנכסים הישנים נשארים במחזור וגורמים לכאוס ולעומס נוסף על הנזילות. אנחנו בונים מערכות מיגרציה אוטומטיות עם מועד אחרון ושריפה (burning) שפותרות את הבעיה הזו לחלוטין. הצוות שלנו מספק את הפרויקט במפתח מלא, מארכיטקטורת החוזה ועד לפריסה ולתמיכה שוטפת.

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

שאלות נפוצות

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

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

תארו לעצמכם: פרסתם טוקן ERC-20 חדש עם כלכלת טוקן משופרת או תיקנתם פרצת אבטחה קריטית בחוזה ישן. עכשיו אתם צריכים שכל המחזיקים יעברו לטוקן החדש. ללא מנגנון דדליין, חלק מהמשתמשים לעולם לא ימירו—טוקנים ישנים נשארים במחזור, הפרוטוקול חייב להחזיק נזילות לנצח, והשוק סובל ממחזור מקביל של שני נכסים. אנו מפתחים מערכות המרה שפותרות את הבעיה הזו לחלוטין: המרה אוטומטית עם דדליין ושריפה. ב-50+ פרויקטים, פיתחנו ארכיטקטורה סטנדרטית המכסה 90% מהתרחישים. אופטימיזציית גז יכולה לחסוך למחזיקים עד $0.50 לכל עסקה ולפרויקט עד $2,000 על ארכיטקטורת החוזה. העריכו את הפרויקט שלכם ביום אחד—פשוט צרו קשר.

כיצד פועלת מערכת ההמרה: ארכיטקטורת החוזה

המערכת מורכבת משלושה משתתפים: OldToken — ה-ERC-20 הקיים, NewToken — הטוקן החדש עם פונקציית mint או היצע מספק, ו-MigrationContract — חוזה מתווך המנהל את ההמרה, הדדליין והשריפה.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract TokenMigration is Ownable2Step, ReentrancyGuard {
    IERC20 public immutable oldToken;
    IERC20 public immutable newToken;
    uint256 public immutable migrationDeadline;
    uint256 public immutable migrationRatio; // новых токенов за 1 старый (18 decimals)
    uint256 public totalMigrated;
    bool public unmigatedBurned;

    event Migrated(address indexed user, uint256 oldAmount, uint256 newAmount);
    event UnmigratedBurned(uint256 amount);

    constructor(
        address _oldToken,
        address _newToken,
        uint256 _deadline, // Unix timestamp
        uint256 _ratio // 1e18 = 1:1, 2e18 = 2 новых за 1 старый
    ) Ownable2Step(msg.sender) {
        require(_deadline > block.timestamp + 30 days, "Deadline too soon");
        oldToken = IERC20(_oldToken);
        newToken = IERC20(_newToken);
        migrationDeadline = _deadline;
        migrationRatio = _ratio;
    }

    function migrate(uint256 amount) external nonReentrant {
        require(block.timestamp < migrationDeadline, "Migration closed");
        require(amount > 0, "Zero amount");
        uint256 newAmount = amount * migrationRatio / 1e18;
        require(newAmount > 0, "Below minimum");
        totalMigrated += amount;
        // Получаем старые токены от пользователя
        oldToken.transferFrom(msg.sender, address(this), amount);
        // Выдаём новые токены
        newToken.transfer(msg.sender, newAmount);
        emit Migrated(msg.sender, amount, newAmount);
    }
}

מדוע Ownable2Step חשוב לחוזי המרה?

Ownable רגיל מאפשר העברת בעלות בשלב אחד: // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable2Step.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract TokenMigration is Ownable2Step, ReentrancyGuard { IERC20 public immutable oldToken; IERC20 public immutable newToken; uint256 public immutable migrationDeadline; uint256 public immutable migrationRatio; // новых токенов за 1 старый (18 decimals) uint256 public totalMigrated; bool public unmigatedBurned; event Migrated(address indexed user, uint256 oldAmount, uint256 newAmount); event UnmigratedBurned(uint256 amount); constructor( address _oldToken, address _newToken, uint256 _deadline, // Unix timestamp uint256 _ratio // 1e18 = 1:1, 2e18 = 2 новых за 1 старый ) Ownable2Step(msg.sender) { require(_deadline > block.timestamp + 30 days, "Deadline too soon"); oldToken = IERC20(_oldToken); newToken = IERC20(_newToken); migrationDeadline = _deadline; migrationRatio = _ratio; } function migrate(uint256 amount) external nonReentrant { require(block.timestamp < migrationDeadline, "Migration closed"); require(amount > 0, "Zero amount"); uint256 newAmount = amount * migrationRatio / 1e18; require(newAmount > 0, "Below minimum"); totalMigrated += amount; // Получаем старые токены от пользователя oldToken.transferFrom(msg.sender, address(this), amount); // Выдаём новые токены newToken.transfer(msg.sender, newAmount); emit Migrated(msg.sender, amount, newAmount); } } . אם תזינו כתובת שגויה, החוזה אבוד לנצח. Ownable2Step (תיעוד OpenZeppelin) דורש מהבעלים החדש לקבל את הזכויות בעסקה נפרדת. לפי מסמכי OpenZeppelin, בעלות דו-שלבית מונעת אובדן שליטה מקרי. עבור חוזה המנהל המרת טוקן עם דדליין, זה קריטי—טעות עלולה לעלות בשליטה על כל ההמרה.

מנגנון שריפה לאחר הדדליין

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

function burnUnmigrated() external onlyOwner {
    require(block.timestamp >= migrationDeadline, "Deadline not reached");
    require(!unmigatedBurned, "Already burned");
    unmigatedBurned = true;

    // Сжигаем старые токены, которые пришли через migrate()
    uint256 oldBalance = oldToken.balanceOf(address(this));
    if (oldBalance > 0) {
        IBurnable(address(oldToken)).burn(oldBalance);
        // Если старый токен не имеет burn() — отправляем на dead address
        // oldToken.transfer(address(0xdead), oldBalance);
    }

    // Возвращаем нераспределённые новые токены в treasury
    uint256 newBalance = newToken.balanceOf(address(this));
    if (newBalance > 0) {
        newToken.transfer(owner(), newBalance);
    }

    emit UnmigratedBurned(oldBalance);
}

מה אם לטוקן הישן אין פונקציית burn()?

רוב הטוקנים המיושנים חסרים פונקציית שריפה. אפשרויות:

  1. שליחה ל-transferOwnership(newOwner) — כתובת שריפה לא רשמית, טוקנים בלתי נגישים לצמיתות.
  2. שליחה ל-function burnUnmigrated() external onlyOwner { require(block.timestamp >= migrationDeadline, "Deadline not reached"); require(!unmigatedBurned, "Already burned"); unmigatedBurned = true; // Сжигаем старые токены, которые пришли через migrate() uint256 oldBalance = oldToken.balanceOf(address(this)); if (oldBalance > 0) { IBurnable(address(oldToken)).burn(oldBalance); // Если старый токен не имеет burn() — отправляем на dead address // oldToken.transfer(address(0xdead), oldBalance); } // Возвращаем нераспределённые новые токены в treasury uint256 newBalance = newToken.balanceOf(address(this)); if (newBalance > 0) { newToken.transfer(owner(), newBalance); } emit UnmigratedBurned(oldBalance); } — רק אם הטוקן מאפשר העברה לכתובת אפס (רבים בודקים 0x000...dEaD).
  3. פונקציית שריפה מותאמת אישית ב-MigrationContract דרך address(0) — רק אם לחוזה ההמרה יש BURNER_ROLE.

השוואת אפשרויות שריפה לטוקנים ללא burn

שיטה הפיכות כתובת סיכונים
העברה לכתובת מתה לא 0x000...dEaD לא רשמי, עלול להימחק
העברה לכתובת address(0) לא 0x000...000 חוזים רבים בודקים != 0
קריאה ל-burnFrom עם תפקיד כן, אם התפקיד נשלל שריפה פנימית דורש הגדרת תפקיד

השוואת שיטות המרה

שיטה גז למשתמש נדרש Approve? סיכון דדליין מתאים ל
ישירה (transferFrom) גבוה (2 עסקאות) כן טוקנים מיושנים נשארים אצל המשתמש מקרים פשוטים, ERC-20 עם burn
Snapshot + Merkle Proof נמוך (1 עסקה) לא טוקנים לא נמשכים, דורש אמון לאחר פריצות, שדרוגים ללא חלון זמן
שריפה דרך כתובת מתה בינוני (1 עסקה) לא בלתי הפיך כשאין פונקציית burn

כיצד פועלת המרת Snapshot (Merkle Proof)

אם ההמרה מבוססת על snapshot (יתרות בבלוק מסוים לפני פריסת החוזה החדש), משתמשים לא שולחים טוקנים ישנים—הם מוכיחים זכאות לטוקנים חדשים דרך Merkle Proof. זה מפחית עלויות גז ב-40-60% לעומת המרה ישירה. המרה ישירה עם transferFrom דורשת שתי עסקאות—approve ו-migrate. המרת Snapshot עם Merkle Proof מהירה פי 2, דורשת רק עסקת תביעה אחת, ועלויות הגז מופחתות פי 2-3. אנו משתמשים בספריית OpenZeppelin MerkleProof לאימות.

contract SnapshotMigration is Ownable2Step {
    bytes32 public immutable merkleRoot;
    mapping(address => bool) public claimed;

    constructor(bytes32 _merkleRoot, uint256 _deadline) {
        merkleRoot = _merkleRoot;
        migrationDeadline = _deadline;
    }

    function claim(uint256 amount, bytes32[] calldata proof) external {
        require(block.timestamp < migrationDeadline, "Expired");
        require(!claimed[msg.sender], "Already claimed");
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
        require(MerkleProof.verify(proof, merkleRoot, leaf), "Invalid proof");
        claimed[msg.sender] = true;
        newToken.transfer(msg.sender, amount);
        emit Claimed(msg.sender, amount);
    }
}

צור את עץ ה-Merkle מחוץ לרשת באמצעות to != address(0) או סקריפט מותאם אישית המבוסס על snapshot יתרות. ה-snapshot נלקח דרך The Graph subgraph או שאילתת צומת ארכיוני.

כיצד מטפלים בטוקנים בחוזי Vesting במהלך ההמרה

אם טוקנים ישנים מוחזקים בחוזי vesting, הם לא ניתנים להמרה ישירה על ידי משתמשים. אפשרויות:

  1. פונקציית אדמין מיוחדת שממירה טוקנים ישירות מחוזה ה-vesting (דורשת אינטגרציה עם חוזה ה-vesting הספציפי).
  2. המרה אוטומטית דרך Tenderly Web3 Actions או keeper לאחר פקיעת ה-vesting.

התראות משתמשים ומעקב התקדמות

החוזה צריך לפלוט אירועים עם מידע מספק לבניית לוח מחוונים:

event MigrationProgress( uint256 totalMigrated, uint256 totalOldSupply, uint256 deadline, uint256 timestamp ); 

Subgraph ב-The Graph מתעד אירועים ומספק API מסוג GraphQL לפרונטאנד: אחוז ההמרה שהושלם, מספר כתובות ייחודיות שהומרו, קינטיקה לאורך זמן.

נקודה מעשית חשובה: מחזיקים גדולים (>1% מההיצע) צריכים לקבל הודעה ישירה לפני השקת ההמרה הציבורית. בורסות, פרוטוקולים, קרנות—ייתכן שיש להם תהליכים פנימיים שלוקחים זמן. הדדליין צריך לאפשר לפחות 90 יום אפילו להמרות פשוטות.

מה אנו מספקים: חבילה מלאה

העבודה כוללת:

  • פיתוח חוזי חכמים להמרה (Solidity 0.8.x, OpenZeppelin).
  • אינטגרציה עם הטוקן הקיים (OldToken) ופריסת החדש (NewToken).
  • הגדרת מנגנון דדליין ושריפה.
  • פיתוח המרה מבוססת snapshot (Merkle Proof) אם נדרש.
  • Subgraph לניטור ולוח מחוונים בפרונטאנד (React + The Graph).
  • ביקורת חוזה עם דוח (בשיתוף מבקרים מוסמכים).
  • תמיכה לאחר ההמרה למשך 30 יום.
  • תיעוד למשתמשים והוראות אינטגרציה.

לוחות זמנים ועלות

לוחות פיתוח: 3-5 ימי עסקים למערכת המרה בסיסית, 7-10 ימים למבוססת snapshot עם Merkle Proof ו-subgraph. העלות מחושבת באופן אישי—בקשו הצעה מסחרית. העריכו את הפרויקט שלכם בחינם—המהנדסים שלנו עם 10+ שנות ניסיון בפיתוח בלוקצ'יין ינתחו את הארכיטקטורה שלכם ויציעו פתרון אופטימלי. בקשו ייעוץ עכשיו.