Add a new currency (fiat or crypto)¶
Goal: add support for a new fiat or crypto currency (analogous to the existing DBC, USDT, BTC, etc.). Audience: customer engineering team adding a new currency for deposits, gameplay, withdrawals, leaderboards. Time: 1–2 weeks. Friction: medium-high — touches Prisma enums, every payment provider mapping, the FE currency picker, jurisdictional whitelist.
What you'll change¶
| Layer | Path | Action |
|---|---|---|
| Currency enum | libs/_prisma/src/schema/api.prisma:70 (enum CurrencySymbol) |
Add the new symbol. Run migration. |
| Crypto config (if crypto) | libs/_prisma/src/schema/api.prisma:184 (model CryptoCurrencyConfig) |
Insert a new row via seed or admin API. |
| Exchange-rate provider | apps/api/src/exchange-rates/provider/coingecko/ |
Add the CoinGecko id mapping. |
| Accounting helpers | libs/accounting/src/currency/ |
Verify rounding / precision rules. |
| Payment provider mappings | per-provider apps/api/src/payment/provider/integration/<provider>/ |
Confirm the new currency is supported by each enabled provider; map vendor codes. |
| Game currency support | libs/games/src/house-games.config.ts (per-game minBet / maxBet) |
Set bet bounds for the new currency. |
| FE currency picker | ebit-fe/src/components/... (search CurrencySymbol, currency selector) |
Display + selection. |
| FE i18n | ebit-fe/messages/{locale}.json |
Currency-name translations. |
| Compliance / jurisdictional matrix | {{TBD}} (docs/security-register?) |
Whitelist where the currency can be deposited / used. |
Canonical references¶
- Enum —
libs/_prisma/src/schema/api.prisma:70definesCurrencySymbol. Verified migrations:add_evo_currency(2025-01-15),add_dbc_currency(2025-03-12),drop_currency(2024-12-09). Pattern: add the enum value, write a migration that inserts a config row. - CryptoCurrencyConfig model at
libs/_prisma/src/schema/api.prisma:184keeps per-currency metadata (e.g. precision, network mapping). Fiat currencies typically don't need a row here; crypto does. - Exchange-rate provider at
apps/api/src/exchange-rates/provider/coingecko/calls CoinGecko by currency id (e.g.bitcoin,tether,usd-coin). - Existing currencies in the codebase: search
CurrencySymbol\.inapps/api/src/. The DBC / EVO additions are recent and provide a fresh template.
Steps¶
1. Pre-flight [non-engineering]¶
- [ ] Confirm with the customer: which jurisdictions accept this currency for play?
- [ ] Confirm: which payment providers (CCPayment, NowPayments, SkinDeck, ...) support deposits / withdrawals in it? Document the matrix.
- [ ] Confirm: source of exchange rate (CoinGecko id, or an alternative oracle). For fiat, CoinGecko also supports most fiat pairs.
- [ ] Confirm: precision / smallest unit (e.g. BTC has 8 dp; some tokens have 18 dp). Mismatches break accounting.
- [ ] Confirm: regulatory classification (security vs commodity vs e-money) for each market — has compliance impact.
- [ ] Get sign-off: legal / compliance, finance.
2. Add the Prisma enum value [needs migration window]¶
Edit libs/_prisma/src/schema/api.prisma:70:
enum CurrencySymbol {
// existing values…
USDT
BTC
ETH
DBC
EVO
// NEW:
YOURCURRENCY
@@map("currency_symbol")
@@schema("public")
}
Generate the migration:
Adding a Postgres enum value is non-blocking. The migration completes in seconds even on a busy database.
3. Insert the CryptoCurrencyConfig row (crypto only)¶
If the new currency is crypto, the seed at libs/_prisma/src/seed/ needs a CryptoCurrencyConfig entry. Verified pattern via existing migrations (add_dbc_currency, add_evo_currency).
For fiat, skip this step.
4. Add the CoinGecko mapping¶
Edit apps/api/src/exchange-rates/provider/coingecko/const.ts (or the equivalent — verify by grepping CurrencySymbol inside apps/api/src/exchange-rates/):
export const COINGECKO_ID_MAP: Record<CurrencySymbol, string> = {
// existing…
[CurrencySymbol.YOURCURRENCY]: 'your-coingecko-id',
};
Validate the id by curl:
5. Update accounting helpers¶
Open libs/accounting/src/currency/. Verify:
- Currency precision is set correctly (the smallest displayable / settle-able unit).
- Rounding mode is consistent with existing currencies (typically half-up).
If the new currency has unusual precision (e.g. a token with 18 dp), add a precision override.
6. Confirm payment provider support¶
For each enabled payment provider (CCPayment, NowPayments, SkinDeck, customer's new provider), confirm:
- The provider supports the new currency (check provider docs / sandbox).
- The provider's currency code maps to our
CurrencySymbol(e.g. provider's"USDT_TRC20"→ ourUSDT).
Edit each provider's currency-mapping file. Locations:
apps/api/src/payment/provider/integration/ccpayment/utils.ts(orconst.ts).apps/api/src/payment/provider/integration/nowpayments/utils.ts.apps/api/src/payment/provider/integration/skindeck/....
If a provider does not support the new currency, the deposit screen must hide that provider for the new currency. Verify the FE currency-provider compatibility logic.
7. Update house-game bet bounds¶
For each game in libs/games/src/house-games.config.ts, ensure the new currency has min/max bet entries:
minBet: {
[CurrencySymbol.USDT]: '0.10',
[CurrencySymbol.YOURCURRENCY]: '0.0001', // adjust per token economics
},
maxBet: {
[CurrencySymbol.YOURCURRENCY]: '100.0',
},
Without these the bet validator BetAmountValidationService rejects bets in the new currency.
8. Frontend currency picker¶
Search ebit-fe/src/ for CurrencySymbol or the currency-picker component. Typical hits:
- A
<CurrencyPicker>component reading the list of supported currencies from a backend endpoint. - A balance display using
useFormatter().number(amount, { style: 'currency', currency }).
If the backend's "supported currencies" response now includes the new symbol, the FE picker auto-populates. Verify:
(Path verified in docs/api-reference/api.md "Currency" tag.)
9. Translations for the new currency name¶
Edit ebit-fe/messages/{en,de,...}.json:
10. Jurisdictional whitelist¶
{{TBD: confirm with security review}} — jurisdictional gating is currently spread across:
- Geo-restriction config (per
apps/api/src/system/...— searchCountry,GeoRestriction). - Per-provider whitelists.
- Feature-flag gating (
enable-feature-flag.md).
For a new currency, the safest path is a feature flag:
- Create
currency-yourcurrency-enabledin GitLab Unleash. - Default off.
- Gate the currency in the supported-list endpoint behind the flag (also gate the currency-picker entry on the FE).
- Enable for the customer's environment + cohort.
11. Tests¶
- Exchange rate fetch returns a number for the new currency.
- Accounting helpers round + format correctly.
- Bet validator accepts a bet inside
[minBet, maxBet]for the new currency, rejects outside.
12. Update the API surface SOT¶
The OpenAPI changes are minor (new enum value in a few schemas) but the diff makes the change auditable. Append a docs/api/changelog.md entry: "Added currency YOURCURRENCY to CurrencySymbol enum; min/max bet bounds set for all house games."
Verification¶
- Currency listing:
GET /currencyreturns the new symbol. - Exchange rate:
GET /exchange-ratesreturns a non-null rate for the new currency. - Deposit: in the FE wallet, the new currency appears as a deposit option. Provider redirect works.
- Bet: a bet in the new currency validates (within bounds) and settles correctly. Balance updates.
- Withdrawal: withdrawal screen shows the new currency. Provider supports the withdrawal.
- Leaderboard / aggregates: existing leaderboards display amounts in the new currency without breaking (verify per-currency leaderboards if those exist).
Notes / known gaps¶
- Migration of historical balances: users who held a different currency don't get auto-converted. Plan messaging.
- Tax reporting: if the customer ships tax reports, confirm the new currency is recognised by the tax module (out of scope for this recipe).
- Adverse selection: adding a currency with high volatility (memecoin, etc.) can shift edge across bet types. Coordinate with the casino-math team.
- The naming convention is enum value = display symbol (BTC, USDT, DBC). Don't introduce lowercase or special-case names.
Cross-links¶
integration-cookbook.md— index.add-payment-provider.md— the new currency may require a new provider.docs/api-reference/api.md→ tagsCurrency,Exchange Rates API,Payments API.docs/data-model/—CurrencySymbol,CryptoCurrencyConfig,Wallet/UserBalance.docs/security-register.md— jurisdictional gating for new currencies.- Existing migrations:
libs/_prisma/src/migrations/{20250115_add_evo_currency,20250312_add_dbc_currency}/.