הטמעת היסטוריית עסקאות בארנק קריפטו למובייל
המשתמש פותח את הארנק ורואה רשימה ריקה — היתרה מוצגת, אך ההיסטוריה חסרה. זה קורה כאשר צבירת נתוני הבלוקצ'יין מוגדרת בצורה שגויה: עסקאות פנימיות אינן מתועדות, העברות ERC-20 אינן מפוענחות, או נתונים מרשתות שונות אינם מנורמלים. ללא יומן עסקאות תקין, המשתמש אינו יכול לאמת קבלה או לאשר שליחה, מה שפוגע באמון באפליקציה. אנו יודעים כיצד לבנות מערכת משנה אמינה: אנו מנתחים קריאות גולמיות דרך צמתי RPC, מפענחים נתוני קלט של חוזים חכמים, מחשבים שווי דולרי במועד העסקה, ושומרים הכל במטמון מקומי. התוצאה היא תגובה מהירה גם במצב לא מקוון וחיסכון משמעותי בקריאות API — עד $2,000 לחודש עבור ארנקים עם נפח פעילות גבוה.
למה צבירת נתונים?
צמתי RPC אינם יכולים להחזיר היסטוריה לפי כתובת: eth_getTransactionsByAddress אינו מופיע במפרט Ethereum JSON-RPC. לכן, אנו משתמשים בשירותים ייעודיים, שלכל אחד מהם יש יתרונות וחסרונות משלו.
באילו APIs להשתמש להיסטוריית עסקאות?
השוואה בין האפשרויות הפופולריות:
| API | רשתות נתמכות | מגבלות | מחיר | הערה |
|---|---|---|---|---|
| Moralis | 10+ EVM, Solana | 100 בקשות/שנייה (תוכנית) | מסלול חינמי זמין | רב-רשתי, מחזיר NFT ושווי דולרי |
| Alchemy | 7+ EVM | 300 בקשות/שנייה (בתשלום) | בתשלום מ-$49 לחודש | אנליטיקה מתקדמת |
| Etherscan | Ethereum, BNB | 5 בקשות/שנייה (חינם) | חינם ל-MVP | API פשוט, מטמון חובה |
| The Graph | כל EVM | תלוי במנוי | אירוח חינם (מגבלות) | Subgraph מותאם אישית, שליטה מלאה |
בפועל, ארנק רב-רשתי משלב: Alchemy ל-EVM (Ethereum, Polygon), Solana RPC עם getSignaturesForAddress, ולאחרים — מודולי אינדוקס מותאמים אישית. אנו משתמשים באותה גישה ומתאימים אותה לרשתות שלך. בנפח ממוצע של 1000 עסקאות ביום, הגישה שלנו מפחיתה עלויות API ב-80% בהשוואה לשליפת היסטוריה מלאה בכל פעם — חיסכון של למעלה מ-$1,500 לחודש.
מבנה נתונים ונורמליזציה
עסקאות מרשתות שונות מנורמלות למודל יחיד (Dart עבור Flutter):
class TransactionRecord {
final String hash;
final String chainId;
final TransactionType type; // send, receive, swap, approve, contract_call
final String fromAddress;
final String toAddress;
final BigInt amount; // в wei/lamports/satoshi
final String tokenSymbol;
final String? tokenAddress; // null для native currency
final int decimals;
final DateTime timestamp;
final TransactionStatus status; // confirmed, pending, failed
final BigInt? gasFee;
final double? fiatValueAtTime; // в USD по курсу на момент транзакции
final String? swapFromToken; // для DEX-свопов
final String? swapToToken;
}class TransactionRecord { final String hash; final String chainId; final TransactionType type; // send, receive, swap, approve, contract_call final String fromAddress; final String toAddress; final BigInt amount; // в wei/lamports/satoshi final String tokenSymbol; final String? tokenAddress; // null для native currency final int decimals; final DateTime timestamp; final TransactionStatus status; // confirmed, pending, failed final BigInt? gasFee; final double? fiatValueAtTime; // в USD по курсу на момент транзакции final String? swapFromToken; // для DEX-свопов final String? swapToToken; } היא משימה נפרדת. CoinGecko Historical API (fiatValueAtTime) מספק מחיר אסימון בתאריך ספציפי. עבור שווי דולרי במועד יצירת הרשומה, אנו מבקשים ושומרים במטמון במסד הנתונים המקומי מכיוון ששערים משתנים.
כיצד לפענח סוג עסקה מנתוני קלט?
העברת ETH פשוטה — /coins/{id}/history?date=DD-MM-YYYY, input: "0x" הוא כתובת הנמען. אך העברת ERC-20 נראית כקריאה לחוזה עם to. אנו מנתחים:
TransactionType detectTxType(String inputData, String toAddress, List<String> knownContracts) {
if (inputData == '0x' || inputData.isEmpty) return TransactionType.send;
final selector = inputData.substring(0, 10); // первые 4 байта
const selectors = {
'0xa9059cbb': TransactionType.tokenTransfer, // transfer(address,uint256)
'0x095ea7b3': TransactionType.approve, // approve(address,uint256)
'0x38ed1739': TransactionType.swap, // swapExactTokensForTokens (Uniswap v2)
'0x7ff36ab5': TransactionType.swap, // swapExactETHForTokens
};
return selectors[selector] ?? TransactionType.contractCall;
}כדי לפענח פרמטרים של העברת ERC-20, אנו מנתחים את input: "0xa9059cbb...": כתובת הנמען בבתים 4-35, סכום בבתים 36-67. זה קריטי להצגה נכונה של העברות אסימונים.
יתרונות פגינציה מבוססת Cursor על פני Offset
היסטוריית עסקאות היא append-only: עסקאות ישנות אינן משתנות. האסטרטגיה שלנו: שמירת הכל ב-SQLite (drift), בעדכון מבקשים רק חדשות (מהבלוק האחרון הידוע). זה מפחית עומס API פי 5-10, מהיר פי 5 מרענון מלא בכל פעם, ומאיץ את ממשק המשתמש.
דוגמת יישום פגינציה ב-Flutter
פגינציה בממשק המשתמש: TransactionType detectTxType(String inputData, String toAddress, List<String> knownContracts) { if (inputData == '0x' || inputData.isEmpty) return TransactionType.send; final selector = inputData.substring(0, 10); // первые 4 байта const selectors = { '0xa9059cbb': TransactionType.tokenTransfer, // transfer(address,uint256) '0x095ea7b3': TransactionType.approve, // approve(address,uint256) '0x38ed1739': TransactionType.swap, // swapExactTokensForTokens (Uniswap v2) '0x7ff36ab5': TransactionType.swap, // swapExactETHForTokens }; return selectors[selector] ?? TransactionType.contractCall; } (Android Jetpack Compose) או input (Flutter) עם בקר פגינציה. השתמש בפגינציה מבוססת cursor לפי מספר בלוק או חותמת זמן, לא מבוססת offset, כדי למנוע כפילויות בהגעת עסקאות חדשות:
// Flutter — пагинация с курсором
Future<void> loadMoreTransactions() async {
if (_isLoading || !_hasMore) return;
_isLoading = true;
final oldestTx = _transactions.lastOrNull;
final newTxs = await repository.getTransactions(
address: walletAddress,
before: oldestTx?.timestamp,
limit: 20,
);
_transactions.addAll(newTxs);
_hasMore = newTxs.length == 20;
_isLoading = false;
notifyListeners();
} סינון וחיפוש
סינון לפי סוג, אסימון, תאריך, רשת — מיושם מקומית על נתונים במטמון. LazyColumn תומך בשאילתות WHERE מורכבות עם אינדקסים, כך שחיפוש לפי כתובת או hash עסקה מהיר — אנו משתמשים ב-ListView.builder או בהרחבת FTS5.
מעקב אחר עסקאות ממתינות
עסקה שנשלחה נכנסת תחילה ל-mempool עם סטטוס pending. האלגוריתם המוכח שלנו למעקב אחר אישור:
- לאחר שליחה, הוסף לרשימת הממתינות המקומית.
- מחזורית (כל 10 שניות) קרא ל-
// Flutter — пагинация с курсором Future<void> loadMoreTransactions() async { if (_isLoading || !_hasMore) return; _isLoading = true; final oldestTx = _transactions.lastOrNull; final newTxs = await repository.getTransactions( address: walletAddress, before: oldestTx?.timestamp, limit: 20, ); _transactions.addAll(newTxs); _hasMore = newTxs.length == 20; _isLoading = false; notifyListeners(); }עבור כל עסקה ממתינה. - או הירשם ל-WebSocket
driftובדוק את הרשימה בכל בלוק חדש.
אלגוריתם זה יעיל פי 2 מרענון היסטוריה מלא. אנו מיישמים אותו עם טיימר מותאם אישית והתראות push (APNs/FCM) בעת שינוי סטטוס.
מה כלול
- אינטגרציה עם API של אינדוקסר (Moralis / Alchemy / Etherscan) או GraphQL subgraph
- נורמליזציית עסקאות עם תמיכה במספר רשתות (
LIKE) - פענוח סוגי עסקאות (העברה, אישור, החלפה, קריאת חוזה)
- מטמון מקומי ב-SQLite עם פגינציה מבוססת cursor
- שווי דולרי במועד העסקה דרך CoinGecko
- סינון וחיפוש טקסט מלא
- מעקב אחר עסקאות ממתינות עם התראות push
לוח זמנים
| שלב | לוח זמנים (בלוקצ'יין יחיד) | לוח זמנים (רב-רשתי) |
|---|---|---|
| רשימה בסיסית עם מטמון | 1–2 שבועות | 2–3 שבועות |
| פענוח DEX + שווי דולרי | 2–3 שבועות | 3–5 שבועות |
| סינון מלא + חיפוש | שבוע אחד | 1–2 שבועות |
| סה"כ | 2–3 שבועות | 4–6 שבועות |
העלות מחושבת באופן אישי, תלויה במספר הרשתות ובמורכבות הפענוח. אנו מציעים ביקורת של הפתרון הנוכחי שלך. עם ניסיון של 5+ שנים בפיתוח ארנקים למובייל ולמעלה מ-50 פרויקטים שנמסרו בהצלחה, אנו מבטיחים מודול באיכות גבוהה. צור קשר כדי לדון בפרטים. הזמן אינטגרציית היסטוריית עסקאות לארנק הקריפטו שלך וקבל מודול מוכן תוך 3–5 שבועות. קבל ייעוץ: המהנדסים שלנו ינתחו את הפרויקט שלך ויציעו פתרון אופטימלי.







