פיתוח חוזים חכמים ב-Solidity לרשתות EVM

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

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

שאלות נפוצות

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

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

פיתוח חוזים חכמים ב-Solidity

לקוח מביא חוזה לבדיקה — 800 שורות של Solidity, פריסה ברשת Ethereum mainnet מתוכננת בעוד כמה ימים. בעמוד השלישי של הקוד, עולה דפוס: קריאה חיצונית לפני עדכון מצב, reentrancy קלאסי. לא תיאורטי — אותה תצורה הייתה ב-The DAO, והביאה להפסדים של למעלה מ-60 מיליון דולר (בשערי חליפין נוכחיים). החוזה חוזר לעיבוד מחדש. זהו תרחיש סטנדרטי כאשר הפיתוח חסר גישה שיטתית לאבטחה. בניסיון שלנו, אנו נתקלים בבעיות כאלה באופן קבוע ויש לנו פתרונות מוכחים.

מדוע Reentrancy עדיין מופיע בחוזי Solidity

למרות שההתקפה ידועה כבר זמן רב, גרסאות reentrancy ממשיכות לצוץ. הבעיה אינה חוסר ידע על הדפוס — רוב המפתחים יודעים על Checks-Effects-Interactions. הבעיה היא reentrancy חוצה-פונקציות, ש-ReentrancyGuard של OpenZeppelin אינו מכסה כברירת מחדל.

תרחיש: חוזה A קורא לחוזה B באמצעות call ברמה נמוכה. B הוא טוקן המיישם ERC-777 עם hook של tokensReceived. ברגע ה-hook, A כבר ניכה טוקנים אך עדיין לא שלח ETH. פונקציית המשיכה ב-A אינה חסומה על ידי מגן ה-reentrancy כי המפתח חשב שרק withdraw מוגן. תוצאה: ניקוז יתרות. כמתואר ב-Reentrancy Attack בוויקיפדיה, זהו אחד מווקטורי ההתקפה הנפוצים ביותר.

פתרון: יש ליישם nonReentrant על כל הפונקציות הציבוריות שמשנות מצב ומבצעות קריאות חיצוניות. עבור מערכות מורכבות, השתמשו ב-ReentrancyGuardUpgradeable נפרד עם בדיקות ברמת מודול במקום ברמת פונקציה.

היכן עוד מסתתרות פגיעויות: התנגשות אחסון ו-Gas Griefing

התנגשות אחסון בתבניות proxy: בשימוש ב-Transparent Proxy או UUPS, משתנים מאוחסנים בחריצי אחסון לפי מיקום ההצהרה. אם גרסת יישום חדשה מוסיפה משתנה לפני משתנה קיים, כל האחסון זז. address public owner הופך לזבל שהיה פעם uint256 public totalSupply. כמה פרוטוקולים גילו את הבעיה לאחר שדרוגים כשמיפויים החלו להחזיר ערכים שגויים. ERC-7201 (אחסון עם namespaces) מציל את המצב — משתני היישום מאוחסנים בחריץ שנבחר מראש באמצעות hash של keccak256, מבודדים ממשתני ה-proxy.

Gas griefing באמצעות לולאות בלתי מוגבלות: פונקציה שעוברת על address[] public users ללא מגבלות בטוחה עם 50 משתמשים אך הופכת לווקטור DoS ב-5000. העסקה פוגעת במגבלת ה-gas של הבלוק ומתבטלת. אם הפונקציה קריטית לפרוטוקול, ה-griefing זול לתוקף ויקר לפרוטוקול. פתרון: pagination באמצעות offset/limit או תבנית pull במקום push (משתמשים תובעים תגמולים בעצמם במקום שהחוזה יחלק לכולם).

כיצד אנו כותבים חוזים מקצה לקצה

טכנולוגיות וכלים

כלי הפיתוח העיקרי שלנו הוא Foundry. לא כי זה טרנדי, אלא בגלל יכולות ספציפיות: בדיקות fuzz ישירות בבדיקות באמצעות vm.fuzz, בדיקות fork על מצב mainnet אמיתי באמצעות vm.createFork, ומהירויות קומפילציה מהירות פי 4-5 מ-Hardhat בפרויקטים גדולים.

Hardhat נשאר בטכנולוגיות למשימות שבהן מערכת התוספים חשובה: hardhat-deploy לפריסות ניתנות לשחזור, hardhat-gas-reporter לדוחות gas ב-CI, ואינטגרציית TypeChain.

חוזי בסיס — OpenZeppelin 5.x. איננו עושים fork או משנים פנימיות. אם יש צורך בהרחבת התנהגות — ירושה ו-override עם super._call() מפורש.

ניתוח סטטי: Slither על כל PR, Mythril לביצוע סמלי לפני פריסה. ל-fuzzing של לוגיקה מורכבת — Echidna עם בדיקות מבוססות מאפיינים. Echidna מוצא פי 3 יותר באגים מאשר בדיקות יחידה סטנדרטיות — מבדל מרכזי בגישה שלנו.

תבניות שאנו משתמשים בהן

  • תבנית תשלום Pull — ETH לעולם אינו נשלח ישירות מפונקציית פרוטוקול. יתרות מצטברות במיפוי, משתמשים קוראים ל-withdraw(). זה מבטל מחלקה שלמה של וקטורי reentrancy ופותר בעיות עם חוזי נמען שחוזרים ב-receive(). במקרה אחד, תבנית זו הוכיחה עצמה כבטוחה ב-80% יותר מ-push.
  • Multicall — אצירת עסקאות באמצעות ERC-2771 או יישום מותאם. מפחית קריאות on-chain, קריטי כאשר gas גבוה ב-mainnet.
  • Diamond Pattern (EIP-2535) — למערכות שבהן מספר הפונקציות עולה על מגבלת 24 KB bytecode לחוזה. ארכיטקטורת Facet מאפשרת הוספת פונקציונליות ללא השחתת אחסון. אנו משתמשים בה לעתים רחוקות — רק במקום שבאמת הכרחי בשל מורכבות הביקורת.

כיצד אנו מייעלים Gas בחוזים חכמים

תבנית בעיה פתרון חיסכון ב-Gas
משתנה bool לבד תופס חריץ מלא (32 בתים) אריזה ל-struct עם סוגים סמוכים 15-20k gas בפריסה
קריאת storage בלולאה כל SLOAD = 100 gas (EIP-2929) שמירה במשתנה זיכרון לפני הלולאה עד 80% על הלולאה
string באחסון יקר ולא יעיל bytes32 למחרוזות קבועות חיסכון פי 3-5
שימוש ב-require במקום if revert בדיקות נוספות Inline assembly לבדיקות תכופות 5-10% לעסקה

סידור מחדש של משתנים לאריזת חריצים הוא הדבר הראשון שאנו עושים במהלך ביקורת gas. חוזה עם uint128 a; uint256 b; uint128 c; תופס 3 חריצים. סידור מחדש ל-uint128 a; uint128 c; uint256 b; — 2 חריצים. בפריסה, ההפרש הוא 20-40k gas; על כל SLOAD בנתיבים חמים, זה מורגש.

בפרויקט אחד, הפחתנו gas ב-40% עבור חוזה staking: החלפנו for ב-while, ארזנו structs, השתמשנו במסכות סיביות. gas סופי ~150k במקום 250k. פרוטוקול עם 10,000 משתמשים חוסך סכומים משמעותיים בעמלות מדי חודש. אנו מבטיחים הפחתת gas מינימלית של 20% בכל פרויקט.

מה כלול בעבודה

  • תיעוד ארכיטקטוני (דיאגרמות, פריסת אחסון, ממשקים)
  • קוד מקור עם בדיקות (כיסוי >95%, בדיקות fuzz)
  • ביקורת פנימית עם דוח SWC
  • סקריפטים לפריסה ואימות
  • גישה למאגר ו-CI/CD (במידת הצורך)
  • ייעוץ לאחר פריסה: חודש תמיכה

טעויות פיתוח אופייניות

  • שימוש ב-tx.origin לאימות במקום msg.sender — פותח התקפות דיוג.
  • חוסר בבדיקות address(0) בקונסטרוקטורים ו-setters — מוביל לאובדן שליטה.
  • המרת סוגים מפורשת ללא אימות — גורמת ל-overflow או התנהגות בלתי צפויה.
  • שימוש ב-send() או transfer() במקום call — מגביל gas ל-2300, שובר אינטגרציות multi-sig.

כיצד אנו עובדים

  1. אנליטיקה (1-3 ימים). ניתוח הארכיטקטורה: תפקידים, הרשאות, invariants שהמערכת חייבת לקיים תמיד. Invariants הם הבסיס לבדיקות מבוססות מאפיינים ב-Echidna.
  2. עיצוב (2-5 ימים). דיאגרמת חוזים, פריסת אחסון, ממשקים. בשלב זה, אנו מחליטים על יכולת שדרוג: UUPS, Transparent, או בלתי משתנה. עבור פרוטוקולי DeFi בעלי ערך גבוה, יכולת שדרוג אינה תמיד יתרון מנקודת מבט של אמון.
  3. פיתוח. חוזים + בדיקות ב-Foundry. כיסוי >95% לפי שורות, בדיקות fuzz על כל הפונקציות הציבוריות עם פרמטרים מספריים. בדיקות fork על Ethereum/Polygon mainnet לאינטגרציות עם Uniswap, Aave, Chainlink.
  4. ביקורת פנימית. Slither, Mythril, סקירה ידנית עם רשימת SWC. אינה מחליפה ביקורות חיצוניות אך סוגרת בעיות ברמת חומרה נמוכה/בינונית לפני שהן מתחילות.
  5. פריסה. סקריפטים באמצעות forge script של Foundry עם אימות אוטומטי ב-Etherscan/Polygonscan. פריסה תחילה ל-testnet (Sepolia, Mumbai), ולאחר מכן ל-mainnet עם multi-sig דרך Gnosis Safe.

הערכות זמנים

סוג חוזה זמן ביצוע
ERC-20 עם פונקציות בסיסיות 3-5 ימים
Staking עם תגמולים ונעילות 1-2 שבועות
פרוטוקול DeFi (AMM, lending) החל מ-6 שבועות
ביקורת מלאה של קוד קיים החל מ-5 ימים

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