Розробка системи депозитів/виведення крипто-казино

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи депозитів/виведення крипто-казино
Складний
~3-5 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1288
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Розробка системи депозитів/виводів крипто-казино

Фінансова система крипто-казино є технічно найкритичнішим компонентом. Вона повинна обробляти тисячі транзакцій, підтримувати миттєві депозити, мінімізувати затримку виводів та запобігати помилкам в обліку коштів користувачів.

Архітектура: Internal Ledger

Крипто-казино не зберігає кошти користувачів безпосередньо на блокчейні. Правильна архітектура — internal ledger (внутрішня книга обліку):

Користувач → Deposit Address (blockchain) → Hot Wallet → Internal Balance
                                                          ↓
Вивід: Internal Balance → Hot Wallet → Гаманець користувача (blockchain)

Внутрішній баланс — це запис у базі даних. Реальні монети знаходяться у гарячому гаманці казино. Це стандартна модель для всіх казино та бірж.

Переваги:

  • Миттєві операції в системі (ставки, бонуси, переводи між іграми)
  • Немає необхідності чекати підтвердження блокчейну для кожної ставки
  • Можливість дробових балансів нижче мінімальної суми транзакції

Потік депозиту

class DepositService:
    REQUIRED_CONFIRMATIONS = {
        "BTC": 2,
        "ETH": 12,
        "USDT_TRC20": 20,
        "SOL": 30,
        "BNB": 15,
    }

    async def get_deposit_address(self, user_id: str, currency: str) -> str:
        """Повертає унікальну адресу депозиту для користувача"""
        # Перевіряємо існуючу адресу
        existing = await self.address_repo.get(user_id=user_id, currency=currency)
        if existing:
            return existing.address

        # Генеруємо нову адресу з HD Wallet
        address = await self.wallet_manager.generate_address(currency, user_id)
        await self.address_repo.save(
            user_id=user_id,
            currency=currency,
            address=address
        )
        return address

    async def on_incoming_transaction(self, tx: BlockchainTransaction):
        """Викликається при кожній вхідній транзакції"""
        # Знаходимо користувача за адресою
        address_record = await self.address_repo.find_by_address(
            tx.to_address, tx.currency
        )
        if not address_record:
            return  # Не наша адреса

        # Зберігаємо очікуваний депозит
        deposit = PendingDeposit(
            user_id=address_record.user_id,
            currency=tx.currency,
            amount=tx.amount,
            tx_hash=tx.hash,
            required_confirmations=self.REQUIRED_CONFIRMATIONS.get(tx.currency, 12),
            current_confirmations=tx.confirmations,
            status="PENDING",
        )
        await self.deposit_repo.save(deposit)

    async def on_confirmation_update(self, tx_hash: str, confirmations: int):
        """Оновлення кількості підтверджень"""
        deposit = await self.deposit_repo.get_by_tx(tx_hash)
        if not deposit or deposit.status != "PENDING":
            return

        if confirmations >= deposit.required_confirmations:
            await self.credit_user(deposit)

    async def credit_user(self, deposit: PendingDeposit):
        """Зачислюємо на внутрішній баланс (ідемпотентна операція)"""
        async with self.db.transaction():
            # Перевіряємо що ще не зачислювали (idempotency)
            if await self.deposit_repo.is_credited(deposit.id):
                return

            await self.balance_repo.credit(
                user_id=deposit.user_id,
                currency=deposit.currency,
                amount=deposit.amount,
                reference=f"DEPOSIT:{deposit.tx_hash}",
            )

            await self.deposit_repo.mark_credited(deposit.id)

        # Повідомляємо користувача
        await self.notifier.send_deposit_confirmed(
            user_id=deposit.user_id,
            amount=deposit.amount,
            currency=deposit.currency,
        )

Внутрішній册облікових записів

Весь облік коштів здійснюється через книгу обліку з подвійним записом:

CREATE TABLE ledger_entries (
    id              BIGSERIAL PRIMARY KEY,
    entry_time      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    user_id         UUID NOT NULL,
    currency        VARCHAR(16) NOT NULL,
    amount          NUMERIC(24, 8) NOT NULL,  -- позитивне = кредит, негативне = дебет
    balance_after   NUMERIC(24, 8) NOT NULL,
    type            VARCHAR(32) NOT NULL,  -- DEPOSIT, WITHDRAWAL, BET_WIN, BET_LOSS, BONUS, etc.
    reference_id    VARCHAR(64),           -- tx_hash, bet_id, bonus_id
    description     VARCHAR(255),
    
    INDEX(user_id, currency, entry_time DESC)
);

Кожна операція з балансом створює запис у книзі обліку. Поточний баланс — це сума всіх записів користувача за валютою:

-- Отримання актуального балансу
SELECT currency, SUM(amount) as balance
FROM ledger_entries
WHERE user_id = $1
GROUP BY currency;

-- Або денормалізована таблиця балансів (оновлюється атомарно)
CREATE TABLE user_balances (
    user_id  UUID NOT NULL,
    currency VARCHAR(16) NOT NULL,
    balance  NUMERIC(24, 8) NOT NULL DEFAULT 0,
    locked   NUMERIC(24, 8) NOT NULL DEFAULT 0,  -- у процесі виводу
    PRIMARY KEY (user_id, currency),
    CHECK (balance >= 0),
    CHECK (locked >= 0),
    CHECK (balance >= locked)
);

Потік виводу

class WithdrawalService:
    MIN_WITHDRAWAL = {
        "BTC": Decimal("0.0001"),
        "ETH": Decimal("0.005"),
        "USDT_TRC20": Decimal("5"),
    }

    async def request_withdrawal(
        self,
        user_id: str,
        currency: str,
        amount: Decimal,
        destination_address: str,
    ) -> WithdrawalRequest:
        # Валідація
        if amount < self.MIN_WITHDRAWAL.get(currency, Decimal("1")):
            raise ValidationError(f"Мінімальний вивід: {self.MIN_WITHDRAWAL[currency]} {currency}")

        user_balance = await self.balance_repo.get_balance(user_id, currency)
        if user_balance.available < amount:
            raise InsufficientFundsError()

        # Валідація адреси блокчейну
        if not self.validate_address(destination_address, currency):
            raise ValidationError("Невірна адреса призначення")

        # Перевірка AML
        aml_result = await self.aml_service.check_address(destination_address, currency)
        if aml_result.risk_score > 7:
            raise ComplianceError("Адреса призначення не пройшла перевірку AML")

        async with self.db.transaction():
            # Блокуємо кошти
            await self.balance_repo.lock_funds(user_id, currency, amount)

            # Створюємо заявку
            request = WithdrawalRequest(
                user_id=user_id,
                currency=currency,
                amount=amount,
                destination=destination_address,
                status="PENDING",
                aml_score=aml_result.risk_score,
            )
            await self.withdrawal_repo.save(request)

        # Ставимо в чергу на обробку
        await self.withdrawal_queue.enqueue(request.id)
        return request

    async def process_withdrawal(self, request_id: str):
        """Обробляється воркером з черги"""
        request = await self.withdrawal_repo.get(request_id)

        # Ручна перевірка для великих виводів
        if request.amount_usd > 10_000:
            if not request.manual_approved:
                await self.notify_compliance_team(request)
                return

        # Відправляємо транзакцію з гарячого гаманця
        try:
            tx_hash = await self.hot_wallet.send(
                currency=request.currency,
                to=request.destination,
                amount=request.amount - self.get_network_fee(request.currency),
            )
            await self.withdrawal_repo.mark_sent(request.id, tx_hash)

        except InsufficientHotWalletFunds:
            # Гарячий гаманець потребує поповнення з холодного сховища
            await self.alert_treasury("Hot wallet needs refill")
            await self.withdrawal_repo.mark_queued(request.id)

Управління гарячим/холодним гаманцем

Гарячий гаманець — онлайн гаманець для обробки виводів. Повинен містити лише оперативні резерви: 15–20% від сукупних коштів користувачів.

Холодний гаманець — офлайн сховище. Multi-signature (3 з 5 ключів), ключі зберігаються у різних відповідальних осіб, поповнення гарячого гаманця — ручний процес з кількома підписами.

class HotWalletManager:
    TARGET_BALANCE_PCT = 0.15  # 15% від сукупних депозитів
    LOW_BALANCE_THRESHOLD_PCT = 0.05  # сигнал при < 5%

    async def check_balance_health(self, currency: str):
        hot_balance = await self.get_hot_wallet_balance(currency)
        total_user_balances = await self.balance_repo.get_total_user_balance(currency)

        ratio = float(hot_balance / total_user_balances) if total_user_balances > 0 else 1.0

        if ratio < self.LOW_BALANCE_THRESHOLD_PCT:
            await self.alert_treasury(
                f"Hot wallet {currency} low: {ratio:.1%} of user balances. "
                f"Refill needed: {total_user_balances * Decimal('0.15') - hot_balance:.4f} {currency}"
            )

Звірка

Щоденна звірка внутрішніх балансів з реальними даними блокчейну:

async def daily_reconciliation(self, currency: str):
    """Звіряємо внутрішні дані з blockchain"""
    # Сукупний внутрішній баланс користувачів
    internal_total = await self.balance_repo.get_total_user_balance(currency)

    # Реальний баланс на наших адресах
    hot_balance = await self.wallet.get_balance(currency, 'hot')
    cold_balance = await self.wallet.get_balance(currency, 'cold')
    real_total = hot_balance + cold_balance

    # Очікуючі виводи (ще не відправлені)
    pending = await self.withdrawal_repo.get_pending_total(currency)

    discrepancy = real_total + pending - internal_total

    if abs(discrepancy) > Decimal("0.0001"):
        await self.alert_finance(
            f"RECONCILIATION DISCREPANCY {currency}: {discrepancy}"
        )

Система звірки — страховка від помилок у коді та потенційних зловживань. Будь-яке розходження потребує негайного розслідування.