Настройка приёма платежей в BNB
BNB работает в двух контекстах, которые легко перепутать: нативный BNB на BNB Chain (BSC, chainId 56) и BEP-2 BNB на Binance Chain (старая цепочка, практически устаревшая). В 99% случаев клиент хочет принимать BNB на BSC — именно это и разберём.
Подход 1: Без сторонних провайдеров
Самый прямой вариант — мониторинг входящих транзакций на адрес через BSC ноду или публичный RPC.
Генерация уникального адреса для каждого заказа через HD wallet:
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://bsc-dataseed1.binance.org/");
// Из mnemonic — для разработки. В production — xpub без хранения seed
const masterWallet = ethers.Wallet.fromPhrase(process.env.MNEMONIC!);
function getDepositAddress(orderId: number): string {
return masterWallet.deriveChild(orderId).address;
}
async function waitForPayment(address: string, expectedAmount: bigint): Promise<string> {
return new Promise((resolve) => {
provider.on({ address }, (tx) => {
if (tx.value >= expectedAmount) {
resolve(tx.hash);
}
});
});
}
Подтверждения: на BSC с 21 валидатором и ~3-секундными блоками — ждём минимум 15 подтверждений для сумм до $1000, 30+ для крупных. Реорги на BSC редки, но случаются.
Проверка по polling (надёжнее, чем websocket-подписки на публичных RPC):
async function checkPayment(
depositAddress: string,
expectedWei: bigint,
fromBlock: number
): Promise<boolean> {
const currentBlock = await provider.getBlockNumber();
for (let block = fromBlock; block <= currentBlock; block++) {
const blockData = await provider.getBlock(block, true);
const incoming = blockData?.transactions.filter(
(tx: any) =>
tx.to?.toLowerCase() === depositAddress.toLowerCase() &&
BigInt(tx.value) >= expectedWei
);
if (incoming && incoming.length > 0) return true;
}
return false;
}
Подход 2: Через BscScan API
Проще, не требует собственной ноды, но добавляет зависимость от стороннего сервиса:
async function getIncomingBNB(address: string, startBlock: number) {
const url = `https://api.bscscan.com/api?module=account&action=txlist` +
`&address=${address}&startblock=${startBlock}&endblock=99999999` +
`&sort=asc&apikey=${process.env.BSCSCAN_API_KEY}`;
const { result } = await fetch(url).then(r => r.json());
return result.filter((tx: any) =>
tx.to.toLowerCase() === address.toLowerCase() &&
tx.isError === "0"
);
}
Лимит бесплатного плана BscScan: 5 запросов/сек, 100k запросов/день — для небольших объёмов хватает.
Приём USDT/USDC на BEP-20
Часто нужно принимать не только нативный BNB, но и стейблкоины на BSC. USDT BEP-20: 0x55d398326f99059fF775485246999027B3197955. Мониторинг через Transfer events:
const USDT_BSC = "0x55d398326f99059fF775485246999027B3197955";
const transferInterface = new ethers.Interface([
"event Transfer(address indexed from, address indexed to, uint256 value)"
]);
const filter = {
address: USDT_BSC,
topics: [
ethers.id("Transfer(address,address,uint256)"),
null,
ethers.zeroPadValue(depositAddress, 32),
],
};
provider.on(filter, (log) => {
const { from, to, value } = transferInterface.parseLog(log)!.args;
console.log(`Received ${ethers.formatUnits(value, 18)} USDT from ${from}`);
});
Sweep и сбор средств
После подтверждения платёж нужно перевести в основной cold/hot wallet. Для нативного BNB это простая транзакция. Учитывайте, что для sweep необходимо оставить BNB на газ (~0.0005 BNB при 3 gwei gasPrice и 21000 gas limit).
Для автоматического sweep деривированных кошельков нужен cron-воркер, который проверяет балансы deposit адресов и переводит накопленное.
Ориентиры по срокам
Базовая настройка приёма нативного BNB с webhook-уведомлением: 1 день. Добавление BEP-20 токенов (USDT, USDC) и автосбор: ещё 1–2 дня. Интеграция в существующий бекенд зависит от его архитектуры.







