פיתוח טוקן רפלקציה: צווארי בקבוק במכניקה
פיתוח טוקן רפלקציה מבטיח פשטות: במקום מעבר על כל המחזיקים, החוזה מחזיק מכפיל משותף ומזכה את כולם בבת אחת, בזמן קבוע. כל עוד יש עשרות כתובות, ההעברות עוברות בצורה חלקה, והיתרות המחושבות תואמות את בפועל.
באלף המחזיקים הראשון, מכניקת ההפצה מתפצלת מהתכנון: עיבוד ההעברה מאט, הסכומים בארנקים אינם תואמים את הצפוי, והעמלה נגבית באופן לא אחיד — מכתובת אחת פעמיים, ומאחרת מעוגלת כמעט לאפס.
הסיבה אינה עומס ברשת. זמן הריצה הקבוע נשמר רק בתוך מרחב הזיכויים: ברגע שהעברה נוגעת בכתובת שמחוצה לו — זוג מסחר, אוצר או ארנק הצוות — החוזה חייב לסנכרן את המצב מול כל המחזיקים. זהו מעבר לינארי נסתר, שעד עתה נראה כמו קבוע.
שגיאות בחוזה החכם מצטברות מעל: עיגול כלפי מטה באריתמטיקה של מספרים שלמים צובר אבק בכתובות שירות, חריגים שסומנו לא נכון שוברים את חישוב המכפיל, וגבולות הערכים יוצרים שחיקת יתרה בהעברה הלוך ושוב.
בהמשך נכנסת עלייה בעומס על המחזיקים: כל העברה יקרה יותר מקודמתה, חלק מהארנקים מקבלים זיכויים באיחור, וחזרה למצב קודם בלתי אפשרית בלי תמונת מצב.
ביקורת הטוקן כאן זולה מכל הגירה: בודקים את האינווריאנטה «סכום היתרות שווה להיצע אחרי כל פעולה», פרופיל הגז באלפי כתובות ותקינות הכתובות המוחרגות. להלן — כיצד זה נסגר.
מה נותנת הפצה בזמן חישוב קבוע
המכניקה הקלאסית של רפלקציה מחשבת מחדש את היתרה של כל מחזיק בכל גביית עמלה — זהו מעבר לינארי על רשימת הכתובות, שבו מספר הפעולות גדל יחד עם הבסיס. אנחנו בונים הפצה על מכפיל מצטבר: החוזה שומר את התוספת הכוללת ליחידת חלק, והיתרה של המשתתף היא חלקו המוכפל בבריכה המשותפת.
ההעברה משנה רק את מונה ההצטברות ושתי רשומות לפי כתובות — מכאן זמן החישוב הקבוע, O(1). זמן עיבוד הפעולה מפסיק להיות תלוי במספר המחזיקים: גם במאות הכתובות הראשונות וגם במאות אלפים היא מתבצעת באותו צעד, והפחתת העלויות בהעברות אינה נתקלת בתקרת גידול הרשת.
עמלה צפויה היא תוצאה של אותו מודל. אחוז הגבייה נקבע כפרמטר של החוזה, אינו מחושב מחדש במהלך העסקה, ולכן השולח והמקבל רואים מראש את הסכום הסופי, ולא מגלים אותו בדיעבד לאחר הביצוע.
מכאן גם נעלמים שני סוגי כשלים. «העברה תקועה» נוצרה כאשר המעבר על הרשימה לא נכנס למגבלת החישוב של הבלוק: העסקה לא עברה, והכספים נותרו במצב תלוי. «אי-התאמת יתרה» הופיעה בגלל שגיאת עיגול מצטברת בפיצול החלקים.
המכפיל המצטבר מחשב בסקאלה של מספרים שלמים עם מרווח דיוק גבוה, והשארית הבלתי ניתנת לחלוקה נשארת בבריכה המשותפת במקום «להידבק» ליתרה של אחר.
ממשקים בסיסיים ובדיקות תקניות נלקחים מהספרייה המהימנה OpenZeppelin, ומעליה אנו כותבים את מכניקת ההפצה עצמה ומטמיעים הגבלות ניתנות לניהול. החוזה אינו שומר כלל רשימת מחזיקים — וזו היציבות: הבסיס מתרחב, ורק ערך המכפיל משתנה, לא לוגיקת החישוב.
אפשרויות מכניקת ההפצה: השוואת גישות
מכניקת ההפצה קובעת מי ומתי משלם על זיכוי התגמול למחזיקים. חישוב אוטומטי מבצע אותו בתוך כל העברה; תשלומים ידניים — בעסקאות נפרדות לפי לוח זמנים; סכימה היברידית מפרידה בין הצבירה לפירעון.
מבחירה זו תלויים עלות ההעברה, התנהגות ארנקי הבורסות ובריכות הנזילות, וכן מידת החלקות שבה החוזה עובר ביקורת.
שלוש סכימות עובדות
הטבלה משווה ביניהן לפי התאמה ומגבלות — בלי קשר לפרויקט מסוים.
| אפשרות מכניקה | מתי מתאימה | מגבלות הגישה |
|---|---|---|
| חישוב אוטומטי בכל העברה | הטוקן נסחר בתדירות גבוהה, יש מחזיקים רבים, והתגמול מופיע ביתרה בלי פעולה של הבעלים | עלות ההעברה גדלה יחד עם מספר הכתובות; בריכות וחוזי מתווך צוברים חלק של אחרים; לא ניתן לתקן שגיאה בנוסחה בדיעבד |
| תשלומים ידניים לפי לוח זמנים | מעגל המחזיקים מוגבל, הזיכויים ניתנים במקבצים, וחשובה הצפויות | היתרה בממשק אינה תואמת את בפועל עד לתשלום; נדרשים מעקב חיצוני אחר חלקים ואישור מקבלים |
| סכימה היברידית | פרויקט גדול: הזיכוי מחושב לפי אינדקס מצטבר ונפדה לפי דרישה או בסף | ביקורת ובדיקות מורכבות יותר; נדרש טיפול נכון בכתובות מוחרגות ובחוזי מתווך |
המגבלות כאן חשובות יותר מהיתרונות: כמעט בלתי אפשרי להחליף מכניקה בטוקן חי בלי להעביר יתרות. לכן את הסכימה מקבעים לפני השקת החוזה ובודקים ברשת בדיקה עם פרופיל העברות אמיתי.
שלבי פיתוח: מפירוק המכניקה ועד ההשקה
סדר העבודה זהה גם לטוקן חדש וגם לשדרוג של טוקן שכבר הושק: קודם מפרקים את המכניקה, ורק אחר כך כותבים קוד. הפרסום ברשת הראשית הוא בלתי הפיך, ולכן כל שלב נסגר בארטיפקט שניתן לבדוק לפני המעבר לשלב הבא.
-
פירוק דרישות ומודל ההפצה. מקבעים כמה נגבה מכל פעולה ובאיזה סדר מזוכה התגמול. בנפרד מפרקים ארנקי בורסות ובריכות נזילות: מכניקה שנכונה להעברה רגילה נשברת במשיכה מבורסה.
-
ביקורת מכניקת הטוקן. מחפשים פונקציות הנפקה נסתרות, הרשאות בעלים בלתי מוגבלות, הצפות בחישוב יתרות ואפשרות לחסימת מכירות. בפלט — רשימת ממצאים עם הערכת סיכון.
-
תכנון הסכימה. נוטלים מקדם רפלקציה אחיד: התגמול מחושב במספר פעולות קבוע ללא תלות במספר המחזיקים. ההפצה אינה מתייקרת עם גידול מספר הכתובות, והתאימות ל-ERC-20 נשמרת.
-
הגדרת החוזה. קובעים שיעורי גבייה, כתובת קרן התגמולים, מגבלות על עסקה. הרשאות הבעלים מוציאות למולטיסיג עם ביצוע מושהה — חשבון אחד שנפרץ לא משנה את הכללים.
-
בדיקה ברשת בדיקה. מריצים העברות, קניות, מכירות, הוספה ומשיכה של נזילות, וכן מקרי קצה: סכומים אפס, העברה לעצמו, ארנק ביתרת אפס.
-
השקה והעברת הפרויקט. מפרסמים את החוזה, מאמתים את קוד המקור, מעבירים גישות ותיעוד: סכימת ההפצה, רשימת הפרמטרים, סדר שינויים ופעולות בעת תקלה.
ערכת מסירה: קוד, סכימות, תיעוד
לאחר השחרור, מכניקת ההפצה לא אמורה להישאר «קופסה שחורה» שרק המחבר יודע לתחזק. אנו מעבירים ערכה מלאה — מקוד המקור והסכימות ועד לתקנונים שלפיהם מבצעים שינויים ללא מעורבותנו. להלן — מה נשאר בידיים ולשם מה נדרש כל ארטיפקט.
- קוד המקור של החוזה עם ארטיפקטי בנייה וערכי גיבוב של הכתובות שנפרסו — לפיהם נבדקת התאמה בין הקוד שפורסם לזה שפועל.
- סכימת זרימות: רגע הזיכוי בעת העברה, פעולות בבריכות נזילות ובבורסות, חישוב היתרה המצטברת וסדר משיכתה.
- מטריצת תפקידי גישה: מי משנה את שיעור ההפצה, מי מחריג כתובות מהזיכוי, מי מפעיל השהיה על פעולות — עם מגבלות ודרישת כמה חתימות.
- תיעוד הטוקן: מכניקת ההפצה, גבולות שינוי השיעור, ההבדל בין יתרת הארנק ליתרה הזמינה למשיכה.
- תקנון עדכון: שינויים רק דרך חוזה מתווך עם החלה מושהית, בדיקה ברשת בדיקה, תוכנית חזרה לגרסה קודמת.
- מערך בדיקות: בדיקות יחידה ומקצה לקצה למצבים שגרתיים ונדירים, כולל יתרות אפס וכתובות מרשימת ההחרגות.
- הוראות השקה: סדר השלבים, מי חותם על העסקאות, מה נבדק ביממה הראשונה לאחר ההרצה.
הערכה אינה כבולה לתשתית שלנו: המאגר, המפתחות והגישות נשארים אצלכם, ולכן את העבודה תוכל להמשיך הצוות שלכם או קבלן אחר.
מקרה בוחן: הפצה בלי גידול בעומס על המחזיקים
הלקוח הגיע עם רעיון מוגמר: טוקן שבו כל המחזיקים מקבלים תגמול ביחס ליתרה.
הגרסה הראשונה של המכניקה הפיצה אותו במעבר ישיר על רשימת הכתובות בכל פעולה — באלפיים מחזיקים העברה נכנסה לשנייה, בחמישים אלף ההמתנה לאישור נמתחה עד חמש עשרה שניות, ושיעור הפעולות שלא הספיקו להתאשר בחלון שהוקצה הגיע ל-6%.
סוג הכשל היה לא נעים: לא ההעברה עצמה נפגעה, אלא אישורה — הכספים ירדו, והפעולה נתקעה. וכל עסקה חדשה הגבירה את העומס על המחזיקים: ככל שסחרו פעיל יותר, כך החזקת הטוקן התייקרה.
את החשבונאות כתבו מחדש לפי עקרון אינדקס: שומרים אינדקס מצטבר של התגמול המופץ, ואת מצב הכתובת מביאים לזמן הנוכחי בעצלתיים — ברגע שנוגעים בחשבון. עלות הפעולה הפכה ל-O(1) והפסיקה להיות תלויה בגודל הבסיס. הממשק נשאר תואם ל-ERC-20, ולכן ארנקים ובורסות חיברו את הטוקן בלי מתאמים מצדם.
לאחר העיבוד מחדש, האישור נשמר בטווח של עד שתי שניות בבסיס של 50 עד 500 אלף כתובות, ושיעור הפעולות הלא מאושרות — 0.2%. אין יותר צורך שהמחזיק ימשוך את התגמול בקריאה נפרדת, ולכן העומס על הארנק אינו גדל יחד עם פעילות הרשת.
לפני הפריסה הרצנו ביקורת ובדיקות על העתק של הרשת: הפצה על חצי מיליון כתובות, מקרי קצה — העברה לכתובת חדשה, יתרת אפס, קריאה חוזרת. משוב הלקוח: «בעבר בדקנו תורים אחרי כל פעילות — עכשיו זו לא משימה. הבורסה חיברה את הטוקן בניסיון הראשון, בלי תיקונים מצדה».
במה שונה חישוב אוטומטי מתשלומים ידניים?
חישוב אוטומטי משנה את היתרה של כל מחזיק ברגע ההעברה: העמלה על ההעברה מתחלקת בין כל הכתובות, והארנק גדל בלי עסקאות נפרדות. תשלומים ידניים בנויים אחרת — מתקבעת תמונת מצב של היתרות בבלוק מסוים, וההפצה מתבצעת בפעולה נפרדת לפי רשימת הכתובות.
חישוב אוטומטי מנצח במקום שבו יש מחזיקים רבים והם לא עוקבים אחרי הטוקן: היתרה מתעדכנת מעצמה, בריכות הנזילות מתחשבות בגידול, ואין צורך למכור דבר.
המגבלה היא מחיר הפעולה: כל עוד יש מאות כתובות, החישוב בכל העברה אינו מורגש; בעשרות אלפים הוא הופך לסעיף ההוצאה העיקרי, וחלק מהחוזים החיצוניים לא יראו את היתרה שהשתנתה ויחשבו את שווי החלק שלא כהלכה.
תשלומים ידניים צפויים יותר: תמונת מצב, רשימת כתובות, הפצה במקבצים — כל פעולה מוערכת מראש, היסטוריית התשלומים נקראת שורה אחר שורה ואינה שוברת את החשבונאות בבורסות, בבריכות ובאגרגטורים. המחיר — השהיה בין הזיכוי לקבלה והצורך להחזיק רזרבה.
גישה היברידית סוגרת את שני הקצוות: החישוב מופעל בהעברות מעל סף נתון או רק עבור חלק המחזיקים הקמעונאי, בעוד חלקים גדולים ושותפים מקבלים תשלומים במקבץ לפי לוח זמנים. העמלה על ההעברה מוגדרת בנפרד — חלק הולך להפצה, חלק לנזילות, חלק לכתובת הפרויקט.
בחירת המכניקה היא תוצאה של הרכב המחזיקים ושל האופן שבו מחושבת העמלה על ההעברה, ולא שאלה של טעם. את ההסתעפות הזו אנחנו מפרקים לפני שורת הקוד הראשונה, ואת התבניות נוטלים ממערכים מהימנים כמו OpenZeppelin, כדי שהחישוב לא יוסיף סוגי כשל חדשים.
שאלות טכניות נפוצות לפני תחילת העבודה
לפני תחילת העבודה אנחנו בודקים לא את העטיפה, אלא את התנהגות ההפצה תחת עומס: כמה עולה העברה כאשר מספר המחזיקים גדל, מה קורה לתגמולים המצטברים בעת שינוי השיעור וכיצד בנויות ההחרגות מהעמלה. להלן — תשובות לספקות שצפים לרוב בשלב הזה.
מה יקרה לתגמולים שכבר נצברו אם משנים את שיעור ההפצה?
מה שכבר נזוכה נשאר אצל המחזיק — השיעור משפיע רק על פעולות עתידיות. היתרה בכתובת נשמרת בנפרד מהתיקון בגין ההעברה האחרונה, ולכן העבר אינו מחושב מחדש, ומה שהורווח לא הולך לאיבוד. לפני השינוי מריצים תרחיש עם שיעורים שונים בסטנד ומשווים יתרות לפני ואחרי.
את מי מחריגים מהעמלה ומה הסיכון לשאר?
בריכת נזילות, האוצר, כתובות שירות. בדיקת ההחרגה מתבצעת בכל העברה, ולכן את הרשימה שומרים קומפקטית: כל קריאת מצב מיותרת מייקרת את ההעברה עבור מחזיקים רגילים. את מערך ההחרגות הסופי מקבעים ומציגים לפני הפריסה.
כיצד נבדקת הכלכלה לפני השקה ברשת הראשית?
הפצה O(1) אינה תלויה במספר המחזיקים: העברה עולה אותו דבר גם במאה כתובות וגם בעשרות אלפים — הסיכון העיקרי של גידול העמלה בהתרחבות מוסר. את הכלכלה מחשבים על נפחי מסחר היסטוריים ועל תרחיש של מחזור אפס: התגמולים לא צריכים להפוך להנפקה אינסופית. בהמשך — ביקורת לוגיקה והרשאות בעלים, הרצה ברשת בדיקה עם בריכה אמיתית, ורק אחר כך הרשת הראשית.
נדון במשימה ונחזור עם תוכנית עבודה
כדי שהערכת הפרויקט תישען על עובדות ולא על ניחושים, בשלב ההתחלה אנחנו צריכים מינימום של נתוני פתיחה: מכניקת הזיכוי, כללי ההחרגות וגישות לתשתית. בדרך כלל אנחנו מבקשים אותם ברשימה אחת — היא גם הופכת לצ'ק-ליסט הקבלה.
- לוגיקת הרפלקציה. למי ועל מה מזוכה חלק מכל פעולה, מאיזה נפח הנפקה מחשבים, האם יש מגבלות ותקופת «האצה» למחזיקים מוקדמים.
- רשימת החרגות. כתובות של בריכות נזילות, חוזים ואוצר שאינם משתתפים ברפלקציה — אחרת הנזילות מתחילה לאכול את עצמה, וזה נראה רק בנתונים חיים.
- רשתות יעד והעברות. היכן אנחנו משיקים, האם נדרשת תמיכה במספר רשתות וכיצד הרפלקציה מתנהגת בהעברות ביניהן.
- ניהול גישות. מי מחזיק במפתחות, האם יש מולטיסיג, מי ובאיזה השהיה יכול לשנות פרמטרים של הזיכוי לאחר ההשקה.
- דרישות הפלטפורמות. אילו בדיקות חובה עבור בורסות ואגרגטורים, האם נדרש פירוק קוד חיצוני לפני הפריסה ובאיזה אופן מפורסמים תוצאותיו.
- עומס ומטריקות. מספר הפעולות הצפוי ביום, מידת הקבילות של העמלה על העברה, דיווח: שיעור המחזיקים שנגבה מהם, נפח הזיכויים, מספר העסקאות שנדחו.
תארו את המשימה — נחזור עם הערכת הפרויקט, תוכנית עבודה לפי שלבים ולוחות זמנים לפיתוח. לאחר ההשקה אנחנו נשארים בתמיכה: עוקבים אחרי פרמטרי הרפלקציה, מגיבים לתקלות ומעדכנים חוזים כשדרישות הפלטפורמות משתנות.







