Первая и самая критическая ошибка при интеграции Bitcoin-платежей – использование единого адреса для всех клиентов. Два пользователя могут прислать одинаковую сумму в одной транзакции, получить несколько UTXO, частично покрывающих сумму, или столкнуться с батчингом со стороны биржи. Правильный подход – генерация уникального адреса на каждый платёж. Из нашей практики: при интеграции для одного маркетплейса мы решили проблему дублирования адресов, что сократило время обработки платежей на 30% и исключило путаницу с зачислениями.
Биткойн: электронная пиринговая система — Сатоши Накамото
Как работает деривация адресов?
Стандарт BIP-32/BIP-44 позволяет из одного master seed генерировать бесконечное дерево адресов детерминированно. Для приёма платежей используется xpub (extended public key) – публичная часть, которую сервер хранит открыто и из которой генерирует адреса. Приватный ключ хранится отдельно (cold storage, hardware wallet) и нужен только для вывода средств.
Master Seed → xpub (m/44'/0'/0') ↓ index=0: 1A1zP1... (payment #1) index=1: 1B2zP2... (payment #2) index=N: ... (payment #N) Путь деривации по BIP-44 для Bitcoin mainnet: m/44'/0'/account'/change/index. Для приёма – change=0, index инкрементируем. Для Native SegWit используется стандарт BIP-84 с путём m/84'/0'/0'.
Как обеспечить уникальность адреса для каждого платежа?
Используйте расширенный публичный ключ (xpub) и индекс, соответствующий ID заказа в вашей базе. Это гарантирует, что клиент не сможет повторно использовать старый адрес, а вы избежите пересечения платежей. Никогда не генерируйте адреса случайным образом – только детерминированно.
Типы адресов: сравнение
| Тип | Формат | SegWit | Экономия комиссии | Рекомендация |
|---|---|---|---|---|
| P2PKH (Legacy) | 1... | Нет | 0% | Не использовать (высокие комиссии) |
| P2SH-P2WPKH (Wrapped SegWit) | 3... | Да | ~20% | Для совместимости со старыми кошельками |
| P2WPKH (Native SegWit) | bc1q... | Да | ~37% | Основной выбор |
| P2TR (Taproot) | bc1p... | Да | ~38% + Schnorr | Для новых проектов с мультиподписью |
Native SegWit (bc1q) даёт экономию до 40% на комиссиях по сравнению с Legacy – это делает его почти в 2 раза выгоднее для клиента. Taproot с Schnorr-подписями позволяет объединять транзакции, что дополнительно уменьшает размер блока на 20% относительно Native SegWit.
Реализация: Node.js + bitcoinjs-lib
import * as bitcoin from 'bitcoinjs-lib' import { BIP32Factory } from 'bip32' import * as ecc from 'tiny-secp256k1' bitcoin.initEccLib(ecc) const bip32 = BIP32Factory(ecc) const NETWORK = bitcoin.networks.bitcoin // или networks.testnet // Один раз: генерация xpub из seed (выполняется в cold storage) // const seed = bip39.mnemonicToSeedSync(mnemonic) // const root = bip32.fromSeed(seed, NETWORK) // const account = root.derivePath("m/84'/0'/0'") // BIP-84 для Native SegWit // const xpub = account.neutered().toBase58() // console.log(xpub) // хранить в .env как BITCOIN_XPUB // На сервере: генерация адреса по индексу function getPaymentAddress(xpub: string, index: number): string { const node = bip32.fromBase58(xpub, NETWORK) const child = node.derive(0).derive(index) // external chain, index N const { address } = bitcoin.payments.p2wpkh({ pubkey: Buffer.from(child.publicKey), network: NETWORK, }) if (!address) throw new Error('Failed to derive address') return address } База данных: схема платежей
CREATE TABLE bitcoin_payments ( id BIGSERIAL PRIMARY KEY, order_id UUID NOT NULL REFERENCES orders(id), address VARCHAR(62) NOT NULL UNIQUE, hd_index INTEGER NOT NULL UNIQUE, amount_sat BIGINT NOT NULL, -- сумма в сатоши status VARCHAR(20) DEFAULT 'pending', -- pending/underpaid/confirmed/expired created_at TIMESTAMPTZ DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL, confirmed_at TIMESTAMPTZ, tx_hash VARCHAR(64) ); CREATE INDEX ON bitcoin_payments(address); CREATE INDEX ON bitcoin_payments(status) WHERE status = 'pending'; Мониторинг транзакций
Для production используйте собственную Bitcoin-ноду с electrs. Публичные API (Blockstream) подходят только для прототипов. Пример WebSocket-мониторинга:
import ElectrumClient from 'electrum-client' const client = new ElectrumClient(50002, 'your-electrs-host', 'tls') await client.connect('payment-monitor', '1.4') async function watchAddress(address: string, onPayment: (tx: any) => void) { const scriptHash = addressToScriptHash(address) // sha256 reversedLE await client.subscribe.on('blockchain.scripthash.subscribe', async (updates) => { const [scripthash, status] = updates if (scripthash === scriptHash && status !== null) { const history = await client.blockchainScripthash_getHistory(scriptHash) onPayment(history) } }) await client.blockchainScripthash_subscribe(scriptHash) } Количество подтверждений
| Сумма | Рекомендуемые подтверждения |
|---|---|
| < $100 | 1 |
| $100 – $1 000 | 3 |
| $1 000 – $10 000 | 6 |
| > $10 000 | 6+ или по бизнес-логике |
0-conf допустим только для физических точек с небольшими чеком и при RBF=false. В e-commerce – ждите хотя бы одно подтверждение.
Как правильно обрабатывать edge-кейсы?
Overpayment – зачислите полную стоимость, а разницу сохраните на балансе пользователя. Возврат возможен только если клиент предоставит адрес для возврата.
Underpayment – заморозьте платёж и попросите доплатить на тот же адрес в течение времени жизни заказа. Не засчитывайте частичную сумму как полную.
Expiry – адрес «просрочен», но транзакция всё же пришла. Храните такие адреса активными ещё 24 часа для зачисления, но не показывайте для новых платежей.
Не доверяйте неподтверждённым транзакциям с флагом BIP125-opt-in-RBF=true. Дождитесь хотя бы одного блока.
Встроенная логика должна различать статусы: pending, underpaid, confirmed, expired. Для underpaid автоматически продлите время ожидания на 15 минут. Для expired – спишите заказ, но сохраните возможность зачисления при поздней транзакции (вручную).
Вывод средств
Для вывода UTXO используйте PSBT с правильным coin selection. Рекомендуем делать sweep раз в сутки скриптом, а не триггерить автоматически на каждый платёж – это сокращает количество транзакций и комиссии.
Что входит в работу
- Проектирование архитектуры HD-кошелька
- Реализация серверной части на Node.js с bitcoinjs-lib
- Интеграция electrs для мониторинга транзакций
- Схема БД и логика обработки платежей (overpayment, underpayment, expiry)
- Документация API и инструкция по эксплуатации
- Обучение администраторов работе с панелью
- Гарантия 30 дней на корректную работу платёжного шлюза
Наши инженеры имеют сертификаты по блокчейн-технологиям и опыт внедрения платежей для 20+ проектов. Оценим ваш проект бесплатно. Получите консультацию по вашему проекту — напишите нам. Закажите внедрение платежного шлюза под ключ.







