Imagine: your crypto casino processes thousands of deposits per day, but one day due to an idempotency bug a user gets a double credit of $50,000. Or a withdrawal hangs for 12 hours due to a suboptimal queue. Such incidents not only undermine trust but can also cost you a license. With over 8 years of experience and 50+ implemented projects for clients from EU, Asia, and CIS, we guarantee architectural reliability — and we know how to avoid these problems at the architecture level.
Below, we break down the key components of a reliable crypto casino financial system: internal ledger, hot/cold wallet, AML check, and regular reconciliation.
Why Internal Ledger is the Foundation of Reliability?
A crypto casino does not store user funds directly on the blockchain. The correct architecture is an internal ledger — an internal accounting book. This is the standard for all crypto exchanges and casinos with multi-million turnovers. Double-entry bookkeeping is the basis of accounting (see Wikipedia).
Advantages of this scheme:
- Instant intra-system operations (bets, bonuses, transfers between games) — no waiting for blockchain confirmations.
- Possibility of fractional balances below the minimum transaction amount.
- Full audit of each operation via double-entry ledger.
A double-entry ledger is significantly more reliable than simple accounting: each operation has a debit and credit, eliminating arithmetic errors at the architecture level. The risk of balance discrepancies is reduced to zero with proper implementation.
How Deposit Receiving is Implemented?
Here is a step-by-step process:
- Generating a unique deposit address for each user via HD Wallet.
- Processing incoming transactions: the system waits for a specified number of confirmations (depends on the network).
- Idempotent crediting to the internal balance — duplicate processing is blocked at the database level.
Example code:
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:
"""Returns a unique deposit address for the user"""
existing = await self.address_repo.get(user_id=user_id, currency=currency)
if existing:
return existing.address
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):
"""Called for every incoming transaction"""
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):
"""Credit to internal balance (idempotent operation)"""
async with self.db.transaction():
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,
)
Internal Accounting: Double-Entry Ledger
All fund accounting is through a ledger with double entry. Each operation is a credit or debit with a reference to the source. We use a denormalized table for quick access to the current balance.
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,
reference_id VARCHAR(64),
description VARCHAR(255),
INDEX(user_id, currency, entry_time DESC)
);
The user's current balance is calculated as the sum of entries, but for performance it is stored in a separate table with balance >= locked checks.
How Withdrawals Work?
class WithdrawalService:
MIN_WITHDRAWAL = {
"BTC": Decimal("0.0001"),
"ETH": Decimal("0.005"),
"USDT_TRC20": Decimal("5"),
}
async def request_withdrawal(self, user_id, currency, amount, destination_address):
if amount < self.MIN_WITHDRAWAL.get(currency, Decimal("1")):
raise ValidationError(f"Minimum withdrawal: {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("Invalid destination address")
aml_result = await self.aml_service.check_address(destination_address, currency)
if aml_result.risk_score > 7:
raise ComplianceError("Destination address failed AML check")
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):
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)
Hot/Cold Wallet Management
Hot wallet — an online wallet for processing withdrawals. It should contain only operational stock: 15–20% of total user funds. Cold wallet — offline storage. Multi-signature (3 out of 5 keys), keys are held by different responsible persons. Refilling the hot wallet is a manual process with multiple signatures.
| Characteristic | Hot Wallet | Cold Wallet |
|---|---|---|
| Access | 24/7 online | Offline, connected as needed |
| Share of funds | 15-20% | 80-85% |
| Signature | Single key (or 2FA) | Multi-signature (3 out of 5) |
| Withdrawal speed | Instant | Requires manual transfer |
| Hacking risk | Higher, but amount limited | Minimal |
class HotWalletManager:
TARGET_BALANCE_PCT = 0.15
LOW_BALANCE_THRESHOLD_PCT = 0.05
async def check_balance_health(self, currency):
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}"
)
Reconciliation: Protection Against Discrepancies
Daily we reconcile internal balances with real blockchain data. Any code error or abuse is instantly detected. An automatic system notifies the finance department for discrepancies over 0.0001 units of currency. In our entire work, we have not allowed a single financial loss for clients thanks to this system. Our systems process up to 50,000 transactions daily with 99.99% uptime.
Which Blockchain Networks Are Supported?
We support Ethereum, Polygon, Arbitrum, Optimism, Base, Solana, BNB Chain, as well as USDT on TRC20 and ERC20. Upon request, we add any EVM-compatible network. The table below shows the minimum withdrawal amounts and the number of confirmations for each network.
| Network | Minimum Withdrawal | Confirmations |
|---|---|---|
| Bitcoin | 0.0001 BTC | 2 |
| Ethereum | 0.005 ETH | 12 |
| USDT TRC20 | 5 USDT | 20 |
| Solana | 0.01 SOL | 30 |
| BNB Chain | 0.01 BNB | 15 |
What's included in the work
- Internal ledger architecture with double entry and idempotency.
- Unique deposit address generation via HD Wallet.
- Incoming transaction processing with configurable number of confirmations.
- Withdrawal processing with AML check integration and task queue.
- Hot/cold wallet management with alerts.
- Daily reconciliation system.
- API documentation and backup strategy.
- Technical support during launch.
How to Get a Reliable System?
Order an audit of your system — we will identify vulnerabilities. Contact us to discuss integration and get a consultation.







