Crypto Casino Game Provider Integration
Crypto casino is technically more complex than regular online casino for one reason: transactions are irreversible and publicly verifiable. If classical casino can rollback payment "for technical reasons", crypto casino cannot. If smart contract paid wrong amount — it's already on-chain. So integration with game providers must be designed with these realities in mind.
Integration architecture: where casino meets provider
Typical game providers
Most major providers (Pragmatic Play, Evolution, Hacksaw, BGaming, Spinomenal) offer Seamless wallet integration or Transfer wallet integration:
Seamless wallet — provider calls your API for each bet and payout in real-time. Your server authorizes debit/credit instantly. Latency critical: provider expects response < 1–2 seconds.
Transfer wallet — player has two balances: your main and temporary at provider. Player transfers themselves before game and withdraws after. Simpler technically, worse UX.
For crypto casino seamless wallet creates challenge: provider expects instant response, but crypto transactions are not instant. Solution — off-chain balance in your database, synchronized with on-chain funds.
Two-level balance
On-chain: user holds USDC in casino smart contract
↕ deposit / withdrawal
Off-chain: your DB stores "game balance" (instant updates)
↕ seamless API calls
Game provider: makes bet/win calls to your API
Deposit: user sends USDC to contract → your service detects on-chain event → credits off-chain balance → user can play.
Withdrawal: user requests withdrawal → you reserve amount → initiate on-chain withdrawal from contract → mark completed on confirmation.
Seamless Wallet API: what your backend must implement
Provider calls your endpoints. Standard set:
POST /wallet/balance — get player balance
POST /wallet/debit — charge bet
POST /wallet/credit — credit win
POST /wallet/rollback — rollback transaction (on provider error)
POST /wallet/check — transaction status check
Key implementation requirements:
Idempotency — provider may send same request multiple times (timeout retry). Each debit/credit has unique transactionId. If already processed — return same result without re-applying:
async function processDebit(req: DebitRequest): Promise<DebitResponse> {
// Check idempotency
const existing = await db.transactions.findByProviderTxId(req.transactionId);
if (existing) {
return { balance: existing.balanceAfter, transactionId: req.transactionId };
}
return await db.transaction(async (trx) => {
const user = await trx.users.lockForUpdate(req.userId);
if (user.balance < req.amount) {
throw new InsufficientFundsError();
}
const newBalance = user.balance - req.amount;
await trx.users.updateBalance(req.userId, newBalance);
await trx.transactions.create({
providerTxId: req.transactionId,
userId: req.userId,
type: "debit",
amount: req.amount,
balanceAfter: newBalance,
});
return { balance: newBalance, transactionId: req.transactionId };
});
}
Atomicity — balance and transaction record updated in single DB transaction. SELECT FOR UPDATE to avoid race conditions on parallel requests.
Rollback — provider calls rollback if error occurs on their side after debit. You must restore balance. Rollback can come hours after original transaction.
On-chain casino contract
Basic structure
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
contract CasinoVault is AccessControl, ReentrancyGuard, Pausable {
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
IERC20 public immutable token;
// Funds for payouts (must always be sufficient)
uint256 public playerFundsReserve;
event Deposit(address indexed player, uint256 amount);
event Withdrawal(address indexed player, uint256 amount);
function deposit(uint256 amount) external nonReentrant whenNotPaused {
token.transferFrom(msg.sender, address(this), amount);
playerFundsReserve += amount;
emit Deposit(msg.sender, amount);
}
// Only operator initiates withdrawal (after off-chain authorization)
function withdraw(
address player,
uint256 amount,
bytes calldata signature // EIP-712 signature from authorizing server
) external nonReentrant whenNotPaused {
_verifyWithdrawalSignature(player, amount, signature);
require(playerFundsReserve >= amount, "Insufficient reserves");
playerFundsReserve -= amount;
token.transfer(player, amount);
emit Withdrawal(player, amount);
}
}
Provably fair mechanics
For on-chain games (not provider's, own) provably fair is important. Classic approach — commit-reveal:
- Server publishes
commitment = keccak256(serverSeed)before round - Player bets with
clientSeed - After bet server reveals
serverSeed - Result =
keccak256(serverSeed + clientSeed + nonce)— verifiable by anyone
For on-chain VRF — Chainlink VRF v2. Randomness request costs LINK, response comes in separate transaction (~1–3 min). Suitable for jackpot and rare events, not real-time slots.
Security and compliance
Limits and restrictions
uint256 public maxDailyWithdrawal = 100_000 * 1e6; // 100k USDC
mapping(address => uint256) public dailyWithdrawn;
mapping(address => uint256) public lastWithdrawalDay;
modifier checkDailyLimit(address player, uint256 amount) {
uint256 today = block.timestamp / 1 days;
if (lastWithdrawalDay[player] < today) {
dailyWithdrawn[player] = 0;
lastWithdrawalDay[player] = today;
}
require(dailyWithdrawn[player] + amount <= maxDailyWithdrawal, "Daily limit exceeded");
dailyWithdrawn[player] += amount;
_;
}
KYC/AML integration
Despite Web3, most jurisdictions require KYC on withdrawals above certain amounts. Chainalysis or Elliptic for on-chain AML screening — check incoming deposits for sanctions or mixer association.
Workflow: wallet screening at first deposit → manual review if risk score > threshold → block withdrawal if confirmed high-risk.
Monitoring and operations
Reserve balance: contract must always have enough funds to cover all off-chain player balances. Automatic monitoring: if playerFundsReserve < sum(all player balances) * 1.05 — alert.
Payout anomalies: unusually large win, suspicious betting pattern (perfect rollback usage), mass withdrawals — trigger manual review.
Provider uptime: if provider unavailable — need graceful degradation, not 500 errors for user. Circuit breaker: after N errors — temporarily disable provider, show "game under maintenance".
MVP development timeline for one provider integration: 6–10 weeks including staging environment testing.







