בדיקות אינטגרציה לחוזים חכמים על Fork של Mainnet
בפיתוח אמיתי, בדיקות יחידה לעיתים קרובות מפספסות שגיאות קריטיות. דוגמה טיפוסית: חוזה סטייקינג עם חלוקת תגמולים עובר את כל בדיקות היחידה, אבל ב-mainnet אחרי שבוע מגלים שאם קוראים ל-compound() ו-withdraw() באותה טרנזקציה דרך אגרגטור, משתמשים מקבלים תגמולים כפולים לאפוקה אחת. הסיבה היא מרוץ מצב בין קריאות וכתיבות בין חוזים שונים. זה הסוג של באג שאנחנו תופסים בבדיקות ברמת המערכת על עותק חי של מצב Ethereum.
מהניסיון שלנו: מעל 80% מהפגיעויות הקריטיות בפרוטוקולי DeFi מתרחשות בממשקי החוזים, לא בתוך פונקציות בודדות. לפי OpenZeppelin, בדיקות אינטגרציה על fork של mainnet הן הדרך היחידה לזהות אותן לפני פריסה. הנתונים שלנו מראים שבדיקות אינטגרציה על fork של mainnet מוצאות פי 3 יותר שגיאות קריטיות מאשר בדיקות יחידה מבודדות. פגיעות reentrancy אחת יכולה לעלות לפרוטוקול עד 2 מיליון דולר — אנחנו מונעים הפסדים כאלה. לדוגמה, לקוח אחד חסך מעל 500,000 דולר על ידי תפיסת מתקפת callback לפני השקה.
איך Fork של Mainnet הופך בדיקות למציאותיות
במקום mocks, אנחנו משתמשים במצב הבלוקצ'יין האמיתי. דרך Hardhat או Foundry, אנחנו עושים fork ל-mainnet בבלוק מסוים (קביעת מספר בלוק מבטיחה שחזוריות). אנחנו בודקים אינטראקציות עם Uniswap V3, Aave V3, Chainlink חיים — לא עם stubs לבדיקה. זה מכסה את כל הניואנסים של טוקנים אמיתיים: fee-on-transfer (USDT), rebase (stETH), blacklist (USDC).
// hardhat.config.ts networks: { hardhat: { forking: { url: process.env.ALCHEMY_URL, blockNumber: 19500000, } } } למה בדיקות אינטגרציה הן קריטיות ל-DeFi
פרוטוקולי DeFi מורכבים מעשרות חוזים שמתקשרים זה עם זה, וכל ממשק הוא פגיעות פוטנציאלית. אנחנו לא בודקים פונקציות בודדות; אנחנו בודקים תרחישים מקצה לקצה:
- DeFi רב-שלבי: הפקדה → אישור LP → סטייקינג → קציר → compound. הבדיקה בודקת את המצב הסופי אחרי השרשרת.
- מתקפת flash loan: דרך Aave V3
// hardhat.config.ts networks: { hardhat: { forking: { url: process.env.ALCHEMY_URL, blockNumber: 19500000, } } }, אנחנו מדמים הלוואה ומנסים לתמרן מחיר ב-AMM. אם החוזה משתמש במחיר ספוט ללא TWAP — הוא פגיע לניצול MEV. - Reentrancy: אנחנו יוצרים חוזה תוקף עם פונקציות callback (
flashLoanSimple()) שקוראות רקורסיבית לחוזה לפני עדכון מצב. - מתקפת סנדוויץ': מדמים תנועת מחיר בין
onERC721Receivedו-approve(), בודקים הגנת slippage.
התוצאות של בדיקות כאלה מונעות הפסדים של מאות אלפי דולרים ללקוחות. כ-90% מהפגיעויות שאנחנו מוצאים שייכות לקטגוריות שבדיקות יחידה לא מכסות. ב-9 מתוך 10 מקרים, שורש הבעיה הוא לוגיקת אינטראקציה, לא באגים ברמת הפונקציה.
| סוג בדיקה | כלי | מכסה |
|---|---|---|
| יחידה | Hardhat / Foundry | לוגיקת פונקציות מבודדת |
| אינטגרציה (mock מקומי) | Hardhat | אינטראקציה בין חוזים עצמיים |
| אינטגרציה (fork של mainnet) | Hardhat / Foundry | אינטראקציה עם פרוטוקולים אמיתיים |
| Fuzzing | Echidna, Foundry forge fuzz | הפרות invariant |
| אימות פורמלי | Certora Prover | תכונות מתמטיות |
השוואת כלים: Foundry מול Hardhat
Foundry מריץ 200 בדיקות ב-15–30 שניות, Hardhat ב-3–5 דקות. עם זאת, Hardhat נוח יותר לתרחישי JavaScript מורכבים ושליטה מדויקת בגז. אנחנו משתמשים בשניהם: Foundry ל-fuzzing מהיר, Hardhat לתרחישים רב-שלביים. מנוע ה-fuzz המובנה של Foundry מאיץ מציאת הפרות invariant פי 10–20 בהשוואה ל-Hardhat עם תוספים. לבדיקות state trie, Foundry מהיר פי 5. אבל יכולות הדיבוג של Hardhat עדיפות לסימולציית סדר טרנזקציות.
איך לבדוק Reentrancy על Fork של Mainnet
אנחנו יוצרים חוזה תוקף שקורא מחדש לחוזה המקורי דרך callback. הבדיקה על fork של mainnet מספקת עלות גז אמיתית — אם הבדיקה עוברת בסביבת mock, היא עשויה לחרוג מהמגבלה ב-mainnet. דוגמה:contract Attacker {
IVulnerable target;
constructor(IVulnerable _target) {
target = _target;
}
function onERC721Received(address, address, uint256, bytes calldata) external returns(bytes4) {
target.withdraw(); // рекурсивный вызов
return this.onERC721Received.selector;
}
} באגים טיפוסיים שהתגלו בפרויקטים
1. **הנחה לגבי סדר אירועים בבלוק.** אם חוזה משתמש ב-`block.number` לחישוב תגמולים, ושתי קריאות באותו בלוק — `block.number` זהה לשתיהן. צריך `block.timestamp` או מונה. 2. **Mocks במקום טוקנים אמיתיים.** טוקן mock תמיד מחזיר `true` ב-`transfer()`. USDT ב-Ethereum לא מחזיר ערך (לא תואם ERC-20). בדיקת mock עוברת, פריסה עם USDT נכשלת. 3. **התעלמות ממגבלת גז.** בדיקת אינטגרציה חייבת למדוד צריכת גז. אם אגרגטור קורא ל-10 בריכות Curve בטרנזקציה אחת, הוא עשוי להגיע למגבלת גז הבלוק (30 מיליון גז). 4. **אין בדיקות לטוקנים עם מקרי קצה.** Fee-on-transfer (PAXG), rebase (stETH), pausable (USDC), blacklist — כל קטגוריה דורשת ערכת בדיקות נפרדת. חיסכון בבדיקות כאלה מוביל לאובדן כספים.מה כלול ולוחות זמנים
- ניתוח חוזים וזיהוי נתיבים קריטיים.
- כתיבת ערכת בדיקות אינטגרציה עם Foundry או Hardhat.
- ביצוע על fork של mainnet עם מספר בלוק קבוע.
- תיעוד בעיות שנמצאו עם המלצות.
- ריצה חוזרת אחרי תיקונים (אבטחת איכות).
- הכשרת צוות הלקוח להרצה ותחזוקת בדיקות.
לוחות זמנים: בדיקות אינטגרציה לפרוטוקול קיים אורכות 2 עד 5 ימי עבודה בהתאם למורכבות. אם בדיקות נכתבות במקביל לחוזים — אנחנו מקצים 30–40% מזמן הפיתוח. העלות מחושבת באופן אישי. לצוות שלנו יש ניסיון של 10+ שנים בפיתוח בלוקצ'יין וביצע בדיקות אינטגרציה ל-50+ פרוטוקולי DeFi. עם 5+ שנים ממוקדות באבטחת Ethereum ו-30+ ביקורות מוצלחות, אנחנו מביאים מומחיות עמוקה במניפולציית אורקל וטיפול ב-reorg של שרשרת.
קבלו ייעוץ — נעריך את הפרויקט שלכם ונציע תוכנית בדיקות אופטימלית. צרו קשר כדי להימנע מטעויות יקרות בייצור. אנחנו מבטיחים את האיכות של כל בדיקה.







