למה חוזה חכם של airdrop נשבר בתשלומים המוניים
הפצה המונית של טוקנים היא לא עסקה אחת, אלא עשרות אלפי קריאות ל-airdrop חוזה חכם, וכל קריאה מיותרת משולמת על ידי השולח. כשההפצה נבנית „בכוח“ — בלולאה על כל רשימת המקבלים בתוך קריאה אחת ב-Ethereum — החוזה נתקל במגבלת הבלוק: חלק מהכתובות עוברות, חלק מתבטלות, והמצב נשאר חלקי.
אחר כך מצטרף הגורם האנושי. שגיאות ברשימת המקבלים — כפילויות, כתובות שאבדו, סכומים ברזולוציה לא נכונה — צפות כבר אחרי הפרסום, כשהתיקון דורש מפיץ נפרד ובדיקה מחודשת.
עסקאות ידניות הופכות תשלומי טוקנים המוניים לפעולה של שעות: סדר nonce מבולבל, חתימות שנתקעו ב-mempool, תשלומים שאי אפשר לשחזר לפי היומן.
מחלקת תקלות נפרדת — הרשאות הנפקה לא סגורות. אם לחוזה המנפיק נשאר מפתח פעיל, מי שקיבל אליו גישה יכול להדפיס עוד טוקנים אחרי ההפצה ולאפס את החלק המחושב של כל משתתף. כאן נשברת לא המכניקה של ההעברה, אלא הכלכלה של כל הקמפיין.
כל שלוש התקלות עוסקות בארכיטקטורת ההפצה, לא בקפדנות של המבצע. נסביר איך זה נסגר ברמת החוזה, רשימת המקבלים והפרדת ההרשאות.
מה משתנה אחרי המעבר לתשלומים מרוכזים
אחרי המעבר לתשלומים מרוכזים, airdrop מפסיק להיות סדרה של העברות והופך לשורש אחד שמפורסם בחוזה חכם. כל משתתף פונה בעצמו לחוזה ומציג הוכחה — ענף של עץ Merkle שמוביל לעלה שלו.
החוזה משווה את הענף לשורש ורק אחר כך מעביר את הטוקנים: זמן ההפצה מפסיק להיות תלוי באורך הרשימה, כי התשלומים מתבצעים במקביל ולא חוסמים זה את זה.
מחלקת התשלומים הכפולים נסגרת ברמת הבדיקה עצמה. העלה נבנה מכתובת וסכום, ועצם הקבלה נרשם בדגל מצב נפרד; קריאה חוזרת עם אותו ענף לא עוברת, גם אם המשתתף טועה ברשת או שולח את העסקה פעמיים. בדיקות ידניות בטבלאות „מי כבר קיבל“ נעלמות — חלק הפעולות הידניות יורד עד להכנת הרשימה ופרסום השורש.
ההוצאות על ביצוע עסקאות מפסיקות לגדול באופן ליניארי עם מספר המקבלים. הפרויקט משלם על פרסום שורש אחד, ואת השאר המשתתפים לוקחים על עצמם; כשהתנאים משתנים, משתנה רק מצב החוזה, ולא כל רשימת הכתובות.
בנפרד, לפני ההפעלה, מתעדים את מועדי הקבלה, את גורל הסכומים שלא נתבעו ואת זכות ההשהיה. דווקא הפרמטרים האלה קובעים איך תסתיים ההפצה — חלוקה צפויה לפי העץ או בירור פניות לתמיכה.
אפשרויות הפצת טוקנים: השוואת גישות
סכימת ההפצה נבחרת לא לפי מראה חיצוני, אלא לפי שלושה דברים: איזה עומס נופל על הרשת, כמה עסקאות יהיה צריך לחתום, וכמה קל לתקן או לבטל סבב. כל אפשרות נבדקת בנוסף להתאמה לטוקן שכבר הונפק, לחוזי ארנק של המקבלים ולכתובות בורסה שאליהן הטוקן ממשיך.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| הפצה מרוכזת דרך עץ Merkle | רשימת המקבלים גדולה, הסכומים ידועים מראש | נשמר שורש העץ בתוספת הוכחות לכל כתובת; שינוי של כל סכום דורש חישוב מחדש של השורש |
| העברות שורה-שורה בלולאה | רשימה של עד עשרות כתובות | העומס על הרשת גדל ליניארית, החבילה מפסיקה להיכנס לבלוק, וביטול מכבה את כל העסקה כולה |
| חוזה הפצה אחיד | חלוקה לפי לוח זמנים, עם תקופות נעילה וסבבים חוזרים | הכספים נמצאים בחוזה, ונדרשים היגיון השהיה ומשיכת חירום |
| הפצה בחלקים, לפי תקופות | צריך לפרוס את החלוקה על פני זמן | יותר עסקאות ורישום, המקבל רואה כמה זיכויים |
| הנפקה ישירה של טוקנים חדשים | טוקן בלי מגבלת הנפקה קבועה, נדרש שליטה מלאה | משנה את הטוקנומיקה המוצהרת ומתקשה לעבור ביקורת לפני רישום למסחר |
העברות שורה-שורה והנפקה ישירה נראות הכי פשוטות בדיוק עד הרשימה הגדולה הראשונה: לולאה על מערך כתובות מהר מאוד נתקלת במגבלת הבלוק, והנפקת טוקנים „תוך כדי תנועה“ סוטה ממה שכתוב בטוקנומיקה.
חוזה הפצה אחיד פותר את עניין לוח הזמנים, אבל מושך את הכספים אל ההיגיון שלו, ולכן בודקים אותו בנפרד בתרחישי השהיה, ביטול תפקיד ומשיכת יתרה — אחרת ההפצה הופכת למאגר לא מבוקר.
שלבי הטמעת חוזה ההפצה
סדר העבודה נבנה כך שעד פרסום החוזה ברשת הראשית אף נתון לא יעורר שאלות. מתחילים בביקורת של סכימת ההפצה — מקור הנתונים על המקבלים, כללי הזיכוי, המגבלות וההגנה מפני קבלה חוזרת. כל שלב מסתיים בארטיפקט שאפשר לאמת בנפרד.
-
ביקורת סכימת ההפצה. משווים את מקור הנתונים על המקבלים לכללי הזיכוי, מתעדים פערים ותנאי גבול. בפלט — היגיון מוסכם ורשימת סיכונים שהיו שוברים את ההפצה.
-
תכנון הרשימה והמבנה. מתוך הייצוא בונים עץ Merkle: מסירים כפילויות וכתובות אפס, בודקים עיגולי סכומים. כל מקבל מקבל הוכחת שייכות, ושורש העץ נרשם בחוזה.
-
הגדרת החוזה. קובעים חלון הפצה, עמלה על קבלה, אפשרות השהיה והפרדת הרשאות. בנפרד בודקים שאי אפשר לקבל את אותו סכום פעמיים.
-
בדיקת נכונות ההפצה. משווים את הסכומים המחושבים לנתוני המקור עד ליחידה האחרונה: שגיאת עיגול בשלב הזה יקרה מכל שגיאה בקוד.
-
רשת בדיקה. פורסים את החוזה, מריצים את כל רשימת המקבלים, בודקים מקרי גבול — פנייה חוזרת, הוכחה זרה, חלון סגור. בוחנים את ההתנהגות בעומס בקשות.
-
העברה לרשת הראשית. מפרסמים את החוזה עם אותם פרמטרים שעברו בדיקה, מזינים את שורש העץ ומעבירים את הרשאות המנהל ללקוח.
-
מסירת החוזה ללקוח. מוסרים קוד מקור, כתובות, הוראות הפצה ונוהל פעולה במצבים שנויים במחלוקת.
מה מועבר ללקוח: קונפיגורציות, סכימות, נהלים
החבילה מועברת לא „בדיבור“: לכל ארטיפקט יש בעלים מוגדר ונוהל עדכון. הלקוח מקבל אפשרות לבצע את הפצת הטוקנים הבאה בכוחות הצוות שלו או למסור את התמיכה לקבלן אחר בלי הנדסה לאחור.
- קוד המקור של החוזה והסקריפטים להכנת הנתונים — עם סכומי ביקורת והוראות לבנייה משוחזרת מסביבה נקייה.
- קונפיגורציית ההפצה: רשימת כתובות וסכומים, שורש עץ Merkle, חלון קבלת הטוקנים, מגבלות לפי כתובת.
- סכימות ההפצה: מאיפה נלקח חתך היתרות, איך מחושבים משקלי הקטגוריות, איך נבדקת היעדרות כפילויות וכתובות „מתות“.
- מדיניות גישה למפתחות: הפרדת תפקידי מנהל ומפעיל, דרישות לחתימה מרובה, סדר סבב והחזקת מפתחות מחוץ לריפוזיטורי.
- נוהל תשלומים: טיפול בטוקנים שלא נבחרו לאחר סגירת החלון, פעולות בכתובות שנויות במחלוקת ומקבלים שגויים.
- תיעוד החוזה: ייעוד הפונקציות והאירועים, קודי שגיאה, אינווריאנטים שנבדקים בבדיקות.
- נוהל הפעלה חוזרת של ההפצה: סדר צעד-אחר-צעד — חתך חדש, בנייה מחדש של העץ, עדכון השורש, ריצה ברשת בדיקה, פרסום.
כל סעיף משויך לתפקיד: מה הלקוח עושה בעצמו, איפה נדרש הצוות שלנו, ואיפה די במהנדס תורן בתמיכה.
מקרה בוחן: הפצה לעשרות אלפי כתובות בלי תקלות
פרויקט השיק הפצת טוקנים ל-38,000 כתובות אחרי החלפת מודל התגמולים. את הסבב הראשון עשו ידנית: ריכזו רשימות בטבלה, שלחו עסקאות בקבוצות של 200 כתובות, ובין קבוצה לקבוצה השוו יתרות.
זה לקח כשני ימי עבודה של מהנדס, ובערך אחת מכל ארבע-עשרה כתובות קיבלה תשלום פעמיים או לא קיבלה כלל — הפער צף רק דרך פניות לתמיכה.
העברנו את ההיגיון למפיץ על עץ Merkle: רשימת המשתתפים והסכומים מגובבת לעץ, לחוזה נכנס רק השורש, והמשתתף בעצמו קורא לקבלה ומציג הוכחת שייכות. קריאה חוזרת, כתובת זרה וסכום ששונה נחסמים בבדיקה, לא בנהלים.
הכנת הסבב התקצרה משני ימים לשלוש שעות: המהנדס אוסף את הרשימה, מחשב את העץ ומפרסם את השורש בקריאה אחת. שיעור הזיכויים השגויים ירד מ-7% לאפס — תשלומים כפולים והחמצות הפכו לבלתי אפשריים מכוח המבנה, לא בזכות קפדנות המפעיל. פניות לתמיכה בנושא „לא הגיע תשלום“ פחתו בסדר גודל: סטטוס הקבלה נראה בחוזה, לא בהתכתבות.
התבנית עמדה בעוד ארבעה סבבי הפצה: רק הרשימה השתנתה, הקוד נשאר אותו דבר. את העמלה על העסקה משלם המשתתף עצמו, ולכן ההפצה לא תלויה ביתרה בארנק אחד, ומחלקת הכשלים „חלק מהכתובות נשארו בלי תשלום“ נעלמה לגמרי.
במה airdrop מרוכז שונה מתשלומים שורה-שורה?
שתי הסכימות נותנות תוצאה אחת — טוקנים בארנקים של המשתתפים — אבל מתנהגות אחרת תחת עומס. ההבדל נראה בשני צירים: כמה עסקאות נשלחות לרשת וכמה קל להוכיח את נכונות ההפצה.
ב-Merkle Distributor הרשימה מתקפלת לשורש עץ אחד שמפורסם בחוזה. המקבל בעצמו קורא לחוזה ומציג הוכחה של הענף שלו — הרשת מעבדת כמה עסקאות כמו מספר האנשים שהגיעו לקבל תשלום, ולא כמו מספר הכתובות ברשימה. יכולת הבדיקה מקסימלית: העץ נבנה מחדש מהקובץ שפורסם ומושווה לשורש.
תשלומים שורה-שורה — לולאת שליחות: עסקה נפרדת ורישום באחסון לכל כתובת. ברשימה של אלפי כתובות החלוקה נמתחת: מקבלים מוקדמים רואים יתרה מיד, מאוחרים — אחרי שעות, וכל הזמן הזה החוזה נשאר נקודת כשל. מנגד, המשתתף לא צריך לעשות דבר בעצמו.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| airdrop מרוכז לפי שורש העץ | רשימות של מאות כתובות, נדרשת יכולת בדיקה ציבורית | השורש אינו ניתן לשינוי, תיקונים — בסבב חדש |
| תשלומים שורה-שורה מהחוזה | רשימה קצרה, המקבלים לא עושים דבר בעצמם | מספר העסקאות כמספר הכתובות |
| סבב מרוכז בתוספת הנפקה משלימה | הרשימה הראשית והכתובות השנויות במחלוקת בנפרד | שני מעגלי רישום, בדיקה מורכבת יותר |
תיקונים אחרי ההפעלה — הפער המרכזי. השורש אינו ניתן לשינוי, ולכן שגיאה בכתובת או בסכום נסגרת בסבב שני עם שורש חדש. בסכימת שורה-שורה מתקנים את הרשימה עד התשלום הראשון, אבל עסקה שכבר יצאה אי אפשר לבטל — את התיקון מבצעים בהעברה נפרדת.
ספקות טכניים לפני הפעלת הפצת טוקנים
לפני פרסום שורש העץ נשארות לצוות כעשר שאלות שלא רואים בדמו: שגיאת הקלדה בכתובת, סבב חוזר, אישור הזכות לתשלום, גישה למפתחות. עוברים עליהן לפני ההפעלה — בבדיקת הקבלה הן צפות הכי часто.
מה עושים עם שגיאת הקלדה בכתובת של מקבל?
חלק משגיאות ההקלדה נחסמות בבדיקת סכום ביקורת, אבל לא כולן — הרשימה עוברת נרמול, הסרת כפילויות והשוואה לייצוא המקורי. אחר כך מקבעים אותה בגיבוב: תיקונים אחרי פרסום השורש נעשים בסבב חדש.
איך יתבצע סבב חוזר והאם לא יהיה תשלום כפול?
לעלה יש דגל תשלום, וקריאה חוזרת מתבטלת ברמת החוזה. סבב חדש מקבל שורש משלו, העלים של הישן לא נכנסים אליו, והיתרה מועברת בפעולה נפרדת.
איך המקבל בודק את הזכות שלו לתשלום?
ההוכחה מחושבת לפי הצמד „כתובת וסכום“ ומושווית לשורש שפורסם. מריצים את הבדיקה מקומית לפני ההפעלה: אם משתתף מהמדגם לא עובר, ההפצה לא יוצאת לדרך.
למי נשארת גישה למפתחות?
מפתח המנהל יכול למשוך את יתרת המאגר, ולכן אינו נשמר אצל אדם אחד. הניהול — דרך חתימה מרובה עם כמה מחזיקים ועיכוב ביצוע: פעולה חשודה נראית ואפשר לבטל אותה.
נדון במשימה: ננתח את סכימת ההפצה שלכם
כדי לחזור עם הערכה ותוכנית, ולא עם מילים כלליות, צריך מינימום נתוני פתיחה. אוספים אותם ברשימה אחת — אם חלק מהנתונים עוד לא קבוע, מסמנים אותם כשאלה פתוחה ומביאים אותם בשלב נפרד.
- רשת ותקן הטוקן: היכן ממוקם החוזה, האם נתמכות העברות עם קריאות צד, ומי מחזיק בהרשאות ההנפקה;
- תמונת מצב של היתרות: בלוק והרגע שלפיהם מחושבים המשתתפים, וכללי הסינון של בוטים וכפילויות כתובות;
- רשימת המקבלים: סדר הגודל, פיזור הסכומים, האם נדרש פרק המתנה ושחרור הדרגתי;
- תפקידים והרשאות: מי מחזיק בחתימה המרובה של המנהל, האם נדרשים time-lock ושלילת הרשאות אחרי ההפצה;
- מכניקת הקבלה: סבב אחד או כמה, אפשר להזין למאגר ולשנות את עץ הזיכויים בין סבבים;
- עומס: כמה פניות לחוזה יגיעו בשעות הראשונות ומי מפזר את השיא;
- קבלה: מי מצד הלקוח מאשר את נכונות הזיכויים.
אחר כך מרכיבים תוכנית עבודה: תכנון כללי הזיכוי ועץ הזיכויים, פיתוח ובדיקות, הפצת בדיקה על סט כתובות מוגבל, ביקורת, ואז הפעלה. ההפצה מתבצעת בשלבים — קודם מאגר קטן, אחר כך הראשי, כדי ששיא הפניות לא ייפול על הרשת ויישאר מרווח לגלגול לאחור.
מסירה לתחזוקה — שלב נפרד, לא פורמליות: מוסרים קונפיגורציות, סכימת הרשאות וחתימה מרובה, סדר עדכון העץ לסבב חדש, הוראות להזנת המאגר ונוהל תגובה לאירועים. תארו את המשימה — נחזור עם הערכה ותוכנית הפעלה, שבה כל סעיף מקבל שלב ואחראי.







