Ledger Wallet Інтеграція
Ledger — найпоширеніший hardware wallet серед користувачів DeFi та професійних трейдерів. Інтеграція з ним відкриває доступ до аудиторії, яка принципово не зберігає ключі в browser extension або mobile app. Це не просто "додати кнопку підключити" — протокол спілкування з пристроєм специфічний, і без розуміння його деталей ви отримаєте нестабільну інтеграцію з поганим UX.
Як працює зв'язок з пристроєм
Ledger використовує кілька транспортних рівнів залежно від середовища:
- WebUSB — прямий USB-з'єднання в браузері (Chrome, Edge). Потребує HTTPS або localhost. Не працює у Firefox з коробки.
- WebHID — новіший API, рекомендується як основний. Підтримує Ledger Nano S Plus та Nano X.
-
Bluetooth — лише Nano X, через
@ledgerhq/hw-transport-web-ble. Нестійкий на мобільних браузерах. -
Node.js HID — для desktop застосунків через
@ledgerhq/hw-transport-node-hid.
Бібліотека @ledgerhq/hw-app-eth інкапсулює APDU-протокол (Application Protocol Data Unit) — низькорівневі команди, якими хост спілкується з пристроєм. Вам не потрібно знати APDU напрямку, але важливо розуміти: кожна операція — це синхронна команда/відповідь, пристрій обробляє їх послідовно.
Отримання адреси та підпис транзакцій
Базовий флоу отримання адреси:
import TransportWebHID from "@ledgerhq/hw-transport-webhid";
import Eth from "@ledgerhq/hw-app-eth";
async function getLedgerAddress(derivationPath: string): Promise<string> {
const transport = await TransportWebHID.create();
const eth = new Eth(transport);
try {
const result = await eth.getAddress(derivationPath, true); // true = display on device
return result.address;
} finally {
await transport.close();
}
}
Derivation path — критичний момент. Стандарт BIP44 для Ethereum: m/44'/60'/0'/0/0. Ledger Live використовує цей path. Старий Ledger Live використовував m/44'/60'/0' (без останніх двох сегментів) — у деяких користувачів адреси саме там. При інтеграції варто підтримувати кілька path-ів з можливістю вибору.
Підпис транзакції потребує серіалізації через RLP та коректної передачі chain ID для EIP-155:
async function signTransaction(tx: TransactionRequest): Promise<string> {
const transport = await TransportWebHID.create();
const eth = new Eth(transport);
// Серіалізуємо транзакцію без підпису
const unsignedTx = ethers.utils.serializeTransaction(tx);
const rlpEncoded = unsignedTx.slice(2); // убираємо 0x
const result = await eth.signTransaction(
"m/44'/60'/0'/0/0",
rlpEncoded,
null // resolution для ERC-20 токенів
);
// Збираємо підпис назад
const signature = {
v: parseInt(result.v, 16),
r: '0x' + result.r,
s: '0x' + result.s,
};
return ethers.utils.serializeTransaction(tx, signature);
}
EIP-712 та Typed Data
Для підпису EIP-712 сповіщень (permit, typed orders) — eth.signEIP712Message. Важливо: старі прошивки Ledger не підтримують eth.signEIP712HashedMessage з повним domain separator. Потрібно перевіряти версію прошивки або використовувати fallback на eth.signPersonalMessage.
Типові проблеми та їх рішення
Пристрій зайнятий іншим застосунком. Ledger може бути підключений до Ledger Live або іншої вкладки. Транспорт повернеться помилка TransportError: Invalid channel. Рішення: обробляти цю помилку явно та показувати користувачу сообщення "Закройте Ledger Live перед використанням".
Blind signing відключений. За замовчуванням Ledger потребує включити "blind signing" в налаштуваннях Ethereum app на пристрої для підпису контрактних транзакцій. Без цього — помилка 0x6a80. Рішення: в UI попереджувати користувача до ініціації транзакції.
Таймаут очікування підтвердження. Користувач не підтвердив на пристрої протягом відведеного часу. @ledgerhq/hw-transport-webhid за замовчуванням не має таймауту — транзакція висить безкінечно. Додавайте Promise.race з таймаутом та кнопкою скасування в UI.
Несумісність з wagmi/viem. Якщо використовуєте wagmi v2, стандартний коннектор для Ledger — через @ledgerhq/connect-kit-loader або кастомний коннектор на базі createConnector. Пряма інтеграція через hw-app-eth працює, але потребує ручного управління provider.
Ledger Connect Kit Інтеграція
Для web-застосунків Ledger пропонує Connect Kit — універсальний спосіб підключення через WalletConnect v2, iframe або прямий WebHID:
import { loadConnectKit, SupportedProviders } from "@ledgerhq/connect-kit-loader";
const connectKit = await loadConnectKit();
connectKit.checkSupport({
providerType: SupportedProviders.Ethereum,
walletConnectVersion: 2,
projectId: "YOUR_WC_PROJECT_ID",
});
const provider = await connectKit.getProvider();
Це спрощує підтримку мобільних користувачів (Nano X через BLE + мобільний браузер), але додає залежність від Ledger's infrastructure.
Stack та таймлайн
| Компонент | Бібліотека |
|---|---|
| WebHID транспорт | @ledgerhq/hw-transport-webhid |
| Ethereum app | @ledgerhq/hw-app-eth |
| Bluetooth | @ledgerhq/hw-transport-web-ble |
| wagmi коннектор | кастомний або Connect Kit |
Базова інтеграція (отримання адреси + підпис ETH/ERC-20 транзакцій + EIP-712) — 1–2 тиж. Включає обробку всіх помилкових сценаріїв та тестування на реальних пристроях (Nano S, Nano S Plus, Nano X).







