Реалізація журналу транзакцій в мобільному криптогаманці
Користувач відкриває гаманець і бачить порожній список — баланс відображається, але журнал операцій відсутній. Така ситуація виникає, якщо агрегація даних з блокчейну налаштована неправильно: не враховуються внутрішні транзакції, не декодуються ERC-20 transfer'и або не нормалізуються дані з різних мереж. Без коректного журналу операцій користувач не може перевірити отримання коштів або підтвердити відправку, що підриває довіру до додатку. Ми знаємо, як побудувати надійну підсистему: парсимо raw-виклики через RPC-ноди, декодуємо input data смарт-контрактів, розраховуємо fiat-еквіваленти на дату транзакції та кешуємо все локально. Результат — швидкий відгук навіть в офлайні та суттєва економія на API-викликах.
Навіщо потрібна агрегація даних?
RPC-ноди не вміють віддавати історію за адресою: eth_getTransactionsByAddress немає в специфікації Ethereum JSON-RPC Spec. Тому ми використовуємо спеціалізовані сервіси, кожен зі своїми компромісами.
Які API використовувати для журналу транзакцій?
Порівняємо популярні варіанти:
| API | Підтримувані мережі | Ліміти | Ціна | Примітка |
|---|---|---|---|---|
| Moralis | 10+ EVM, Solana | 100 req/с (план) | Є безкоштовний тариф | Multi-chain, повертає NFT та фіат |
| Alchemy | 7+ EVM | 300 req/с (платний) | Платно від $49/міс | Розширена аналітика |
| Etherscan | Ethereum, BNB | 5 req/с (безкоштовно) | Безкоштовно для MVP | Простий API, кешування обов'язкове |
| The Graph | Будь-який EVM | Залежить від підписки | Безкоштовний хостинг (ліміти) | Кастомний subgraph, повний контроль |
На практиці в multi-chain гаманці комбінують: Alchemy для EVM (Ethereum, Polygon), Solana RPC з getSignaturesForAddress, для інших — власні модулі індексації. Ми використовуємо такий самий підхід і адаптуємо під ваші мережі. При середньому обсязі 1000 транзакцій на день, використання кешу дозволяє заощадити до $200 на місяць на API-викликах.
Структура даних та нормалізація
Транзакції з різних мереж нормалізуємо в єдину модель (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;
}
fiatValueAtTime — окреме завдання. CoinGecko Historical API (/coins/{id}/history?date=DD-MM-YYYY) дає ціну токена на конкретну дату. Для USD-еквівалента під час створення запису — запитуємо та кешуємо в локальній БД, тому що курси змінюються.
Як декодувати тип транзакції з input data?
Простий переказ ETH — input: "0x", to — адреса отримувача. Але ERC-20 transfer виглядає як виклик контракту з input: "0xa9059cbb...". Парсимо:
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 transfer — парсимо input: адреса отримувача в байтах 4-35, сума — байти 36-67. Це критично для коректного відображення переказів токенів.
Переваги cursor-based пагінації перед offset-based
Історія транзакцій — append-only: старі не змінюються. Стратегія: зберігаємо всі в SQLite (drift), при оновленні запитуємо тільки нові (від останнього відомого блоку). Це в 5-10 разів знижує навантаження на API та прискорює UI. Cursor-based пагінація в 10 разів швидша за offset-based для журналу транзакцій.
Приклад реалізації пагінації на Flutter
Пагінація на UI: LazyColumn (Android Jetpack Compose) або ListView.builder (Flutter) з контролером пагінації. Використовуємо cursor-based за block number або timestamp, не offset-based, щоб уникнути дублікатів при нових надходженнях:
// 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();
}
Фільтрація та пошук
Фільтри за типом, токеном, датою, мережею — реалізуємо локально на закешованих даних. drift підтримує складні WHERE-запити з індексами, тому пошук за адресою або хешем транзакції швидкий — використовуємо LIKE або FTS5 extension.
Алгоритм відстеження pending-транзакцій
Відправлена транзакція спочатку в mempool зі статусом pending. Алгоритм відстеження підтвердження:
- Після відправки додаємо в локальний список pending.
- Періодично (раз на 10 секунд) викликаємо
eth_getTransactionReceiptдля кожної pending. - Або підписуємося на WebSocket
eth_subscribe("newHeads")і при кожному новому блоці перевіряємо список.
Цей алгоритм в 2 рази ефективніший за повне оновлення історії. Ми реалізуємо його з кастомним таймером та повідомленнями через push (APNs/FCM) при зміні статусу.
Що входить в роботу
- Інтеграція з indexer API (Moralis / Alchemy / Etherscan) або GraphQL subgraph
- Нормалізація транзакцій з підтримкою кількох мереж (
>=2) - Декодування типів транзакцій (transfer, approve, swap, contract call)
- Локальний кеш в SQLite з cursor-based пагінацією
- Fiat-еквіваленти на дату транзакції через CoinGecko
- Фільтрація та повнотекстовий пошук
- Відстеження pending транзакцій з push-повідомленнями
Строки
| Етап | Строк (один блокчейн) | Строк (multi-chain) |
|---|---|---|
| Базовий список з кешем | 1–2 тижні | 2–3 тижні |
| DEX-декодування + фіат | 2–3 тижні | 3–5 тижнів |
| Повна фільтрація + пошук | 1 тиждень | 1–2 тижні |
| Разом | 2–3 тижні | 4–6 тижнів |
Вартість розраховується індивідуально, залежить від кількості мереж та складності декодування. Ми маємо 5 років досвіду в розробці криптогаманців та понад 50 успішних впроваджень. Гарантуємо якість коду та підтримку після впровадження. Ми пропонуємо безкоштовний аудит вашого поточного рішення — зв'яжіться з нами, щоб обговорити деталі. Замовте інтеграцію журналу транзакцій у ваш криптогаманець — отримайте готовий модуль за 3–5 тижнів. Отримайте консультацію: наші інженери проаналізують ваш проект та запропонують оптимальне рішення. Зв'яжіться з нами для обговорення деталей.







