Drop a dust-sized change into the fee on an RBF bump and audit every refused bump (B-87, TX-11, TX-24, AUD-40, AUD-09, ADR-19)
`bump_fee` only required `change > fee delta`. A change at the 294 sat minimum (a full-balance
withdrawal) shrank to ~153 sat after the very first minimum bump, relay policy refuses a
replacement with a sub-dust output, and the bumper tried again every 30 seconds for ever, with
nothing but a log line to show for it.
- When what would be left of the reducible output (the user's change, a payout's bump
reserve) is under DUST_LIMIT_SATS the output is dropped and its whole value goes to the fee:
that replacement is valid and the last one possible. If the output does not exist, or even
its whole value is below BIP125's minimum increase (vsize x 1 sat/vB), RbfError. The
recorded fee rate uses the replacement's own, smaller, size.
- RbfError now carries a `reason` (`change_too_small`, `max_fee_rate`, `replacement_rejected`);
RbfBumper._record_failure writes one `rbf_bump_failed` row {pending_transaction_id, kind,
txid, reason, message[:200]} with the row's user_id/round_id, in a transaction of its own,
once per (current txid, reason) - the audit log is the dedupe clock (AUD-09) - and the pending
row is untouched. A new txid or a new reason writes a new row.
- bump_fee's docstring no longer cites the "bet without change" case that B-62 removed.
No existing test changed (all bumps they make leave a change well above dust). New
tests/unit/test_rbf_dust.py: the 294 sat case end to end (recipient untouched, whole change to
the fee, last bump impossible), the exact boundary (leaves 294 kept / leaves 293 dropped), a
change under the minimum increase, a payout's reserve dropped with the winner and fee outputs
byte-identical, and the audit rows for each reason, once per pair, new row on a new txid or
reason, round/user attribution. Mutation-checked: the dust test of the output and the
once-per-pair check each fail tests.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
54dbffb552
commit
ccd15807ed
11 files changed
+440
-108
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# ADR-19 — Ogni transazione utente conserva un'uscita di resto verso l'utente, e un'accelerazione che porterebbe quel resto sotto `DUST_LIMIT_SATS` (294 sat) lo elimina
|
||||
|
||||
- **Stato:** Accettata — implementazione da completare (B-87)
|
||||
- **Stato:** Accettata
|
||||
- **Area:** Economia del gioco
|
||||
- **Fonte di verità per:** la scelta di progetto descritta qui sotto; i requisiti (`PREFISSO-NN`) che la attuano stanno nei documenti di dominio, indicati nelle *Conseguenze*.
|
||||
|
||||
@@ -31,7 +31,4 @@ e di [TX-11](../transazioni-e-riconciliazione.md#rbf-accelerare-una-transazione-
|
||||
utente: la sua uscita riducibile è la riserva di [ADR-17](ADR-17-commissione-pagamento-esce-dalla-quota-vincitore.md).
|
||||
|
||||
*Codice:* `app/wallet/psbt_builder.py:build_signed_transaction` · `app/withdrawals/service.py:request_withdrawal` · `app/tx/broadcast.py:bump_fee` ·
|
||||
*Test:* `tests/unit/test_psbt_builder.py::test_build_signed_transaction_refuses_an_amount_that_would_leave_no_change`, `tests/unit/test_withdrawals.py::test_full_balance_withdrawal_keeps_a_bumpable_change_output`, `tests/unit/test_withdrawals.py::test_a_bet_from_a_balance_equal_to_the_bet_is_refused`
|
||||
*Stato:* da implementare (B-87) · *Oggi:* `bump_fee` richiede solo che il
|
||||
resto superi l'aumento, e può lasciare un resto sotto soglia che nessun nodo
|
||||
inoltra.
|
||||
*Test:* `tests/unit/test_rbf_dust.py::test_a_minimum_change_is_dropped_into_the_fee_by_the_first_bump`, `tests/unit/test_rbf_dust.py::test_the_dust_boundary_of_what_a_bump_leaves`, `tests/unit/test_psbt_builder.py::test_build_signed_transaction_refuses_an_amount_that_would_leave_no_change`, `tests/unit/test_withdrawals.py::test_full_balance_withdrawal_keeps_a_bumpable_change_output`, `tests/unit/test_withdrawals.py::test_a_bet_from_a_balance_equal_to_the_bet_is_refused`
|
||||
+11
-13
@@ -44,9 +44,9 @@ ogni tipo di evento. Le colonne della tabella `audit_log` sono descritte in
|
||||
`app/tx/broadcast.py:RbfBumper._tick`, `app/main.py:lifespan`,
|
||||
`app/rounds/scheduler.py:RoundScheduler._tick`,
|
||||
`app/electrum/listener.py:ElectrumListener._record_reorg`
|
||||
*Stato:* da implementare (B-87, B-90, B-96), per tre degli eventi
|
||||
nuovi · *Oggi:* gli eventi osservativi sono solo i primi quattro e
|
||||
`chain_reorg_detected`.
|
||||
*Stato:* da implementare (B-90, B-96), per due degli eventi
|
||||
nuovi · *Oggi:* gli eventi osservativi sono i primi quattro,
|
||||
`chain_reorg_detected` e `rbf_bump_failed`.
|
||||
|
||||
- **[AUD-04]** Il `payload` è un dizionario serializzato in JSON nella colonna
|
||||
`payload_json`. `created_at` è impostato dall'applicazione, non dal
|
||||
@@ -115,9 +115,9 @@ ogni tipo di evento. Le colonne della tabella `audit_log` sono descritte in
|
||||
`app/rounds/scheduler.py:RoundScheduler._tick`,
|
||||
`app/rounds/scheduler.py:RoundScheduler._close_and_draw` ·
|
||||
*Test:* `tests/unit/test_scheduler.py` (solo `payout_failed`)
|
||||
*Stato:* da implementare (B-87, B-96), per le ultime due letture ·
|
||||
*Oggi:* le letture sono quelle di `payout_failed` e di
|
||||
`draw_baseline_tip_unknown`.
|
||||
*Stato:* da implementare (B-96), per l'ultima lettura ·
|
||||
*Oggi:* le letture sono quelle di `payout_failed`, di
|
||||
`draw_baseline_tip_unknown` e di `rbf_bump_failed`.
|
||||
|
||||
## Catalogo degli eventi
|
||||
|
||||
@@ -590,10 +590,8 @@ flowchart LR
|
||||
nel registro una riga uguale ([AUD-09]); un nuovo fallimento con la stessa
|
||||
coppia va solo nei log, mentre un nuovo txid (dopo un aumento riuscito) o un
|
||||
motivo diverso scrivono una riga nuova.
|
||||
*Codice:* `app/tx/broadcast.py:RbfBumper._tick`, `app/tx/broadcast.py:bump_fee` ·
|
||||
*Test:* —
|
||||
*Stato:* da implementare (B-87) · *Oggi:* l'errore va solo nel log
|
||||
(`could not bump pending_transaction N`), ogni 30 secondi.
|
||||
*Codice:* `app/tx/broadcast.py:RbfBumper._record_failure`, `app/tx/broadcast.py:RbfBumper._tick`, `app/tx/broadcast.py:bump_fee` ·
|
||||
*Test:* `tests/unit/test_rbf_dust.py::test_a_change_too_small_bump_writes_one_rbf_bump_failed_row_per_txid_and_reason`, `tests/unit/test_rbf_dust.py::test_the_maximum_fee_rate_is_reported`, `tests/unit/test_rbf_dust.py::test_a_replacement_the_network_refuses_is_reported_and_leaves_the_row_alone`, `tests/unit/test_rbf_dust.py::test_a_new_txid_or_a_new_reason_writes_a_new_row`
|
||||
|
||||
### Catena
|
||||
|
||||
@@ -636,9 +634,9 @@ flowchart LR
|
||||
`app/rounds/scheduler.py:RoundScheduler._tick`,
|
||||
`app/rounds/confirmation.py:_on_payout_confirmed`,
|
||||
`app/tx/confirmation.py:poll_once`, `app/tx/broadcast.py:bump_fee`
|
||||
*Stato:* da implementare (B-87, B-92, B-94), per i tre fatti che escono
|
||||
dall'elenco · *Oggi:* gli RBF impossibili, la registrazione e il cambio
|
||||
password riuscito non producono alcuna riga.
|
||||
*Stato:* da implementare (B-92, B-94), per i due fatti che escono
|
||||
dall'elenco · *Oggi:* la registrazione e il cambio password riuscito non
|
||||
producono alcuna riga.
|
||||
|
||||
## Log applicativo
|
||||
|
||||
|
||||
+27
-34
@@ -33,7 +33,7 @@ implementato il [piano delle correzioni](piano-correzioni.md).
|
||||
| Limite | Blocca il non presidiato oggi? | Dopo il piano |
|
||||
|---|---|---|
|
||||
| ~~[LIM-01]~~ `drawing` non riprende dopo un errore o un riavvio | Non più (chiuso da B-81) | — |
|
||||
| [LIM-02] RBF di una sola forma (e pagamento senza resto) | **Sì, in caso di congestione della rete** | Chiuso da B-79 e B-87 |
|
||||
| [LIM-02] RBF di una sola forma | Non più il pagamento senza resto (B-79) né il resto sotto soglia (B-87); resta una transazione che esaurisce resto o riserva | Visibile in `rbf_bump_failed`; resta in attesa senza abbandono |
|
||||
| [LIM-03] Attesa in `closing` senza limite di tempo | **Sì, in caso di congestione** | Resta senza limite di tempo per scelta ([ADR-51](adr/ADR-51-dubbio-liberano-mai-fondi.md)); con B-78 e B-87 finisce quando la rete decide |
|
||||
| [LIM-04] Prelievo e RBF mai provati in rete reale | **Sì, come verifica** | Da chiudere con la prova su rete reale ([operativita.md](operativita.md#prova-su-rete-reale)) prima di aprire al pubblico |
|
||||
| ~~[LIM-10]~~ Riorganizzazioni non gestite | Non più (chiuso da B-82 e B-85) | Resta [LIM-24] |
|
||||
@@ -50,38 +50,31 @@ implementato il [piano delle correzioni](piano-correzioni.md).
|
||||
stesso vincitore ([RND-36](ciclo-di-vita-del-round.md)).
|
||||
|
||||
- **[LIM-02]** **L'RBF gestisce una sola forma di transazione**: un'unica uscita
|
||||
di resto verso il mittente, abbastanza grande da assorbire l'aumento. Non c'è
|
||||
il ripiego «aggiungi un'altra moneta». Ogni aumento costa almeno 1 sat/vB
|
||||
sull'intera dimensione della transazione (141 sat per una transazione
|
||||
con un ingresso e due uscite) e si toglie dal resto; quando l'aumento supera
|
||||
il resto, `bump_fee` solleva `RbfError`. Inoltre `bump_fee` **non controlla
|
||||
che il resto ridotto resti sopra la soglia di polvere**: con un resto vicino
|
||||
al minimo di 294 sat ([ADR-19](adr/ADR-19-ogni-transazione-utente-conserva-uscita-resto.md)) già il primo aumento produce un'uscita sotto
|
||||
soglia, che le regole di inoltro standard rifiutano. **Il pagamento del
|
||||
round, nel caso normale, non ha alcun resto** (spende esattamente il
|
||||
montepremi del round, e un resto sotto soglia va alla commissione), quindi
|
||||
non è accelerabile affatto.
|
||||
- *Impatto:* con la rete congestionata una transazione a 1 sat/vB può
|
||||
restare in mempool indefinitamente. Poiché il riconciliatore abbandona solo
|
||||
ciò che il server **non conosce**, una transazione ferma ma presente in
|
||||
mempool non viene mai abbandonata: una scommessa così blocca il round in
|
||||
`closing`, un pagamento così lo blocca in `paying_out`. `RbfBumper`
|
||||
registra un errore ogni 30s.
|
||||
- *Mitigazione attuale:* resto minimo garantito sulle transazioni utente;
|
||||
tetto al fee rate (`MAX_FEE_RATE_SAT_VB`); abbandono dopo 6 ore per ciò che
|
||||
sparisce dalla rete; ritentativo automatico del pagamento dopo un
|
||||
abbandono.
|
||||
- *Stato:* da chiudere con B-87 (la riserva del pagamento, B-79, c'è).
|
||||
- *Per chiuderlo:* ogni pagamento porta un'uscita di riserva che
|
||||
l'accelerazione riduce ([ADR-17](adr/ADR-17-commissione-pagamento-esce-dalla-quota-vincitore.md), B-79); un aumento che lascerebbe un
|
||||
resto sotto `DUST_LIMIT_SATS` elimina il resto e ne versa il valore in
|
||||
commissione, e quella sostituzione è l'ultima ([ADR-19](adr/ADR-19-ogni-transazione-utente-conserva-uscita-resto.md), B-87); ogni
|
||||
`RbfError` e ogni sostituzione rifiutata scrivono `rbf_bump_failed` in
|
||||
audit. Resta accettato, dopo il piano: nessun ripiego «aggiungi un'altra
|
||||
moneta» né CPFP; una transazione che ha esaurito resto o riserva e non
|
||||
conferma nemmeno al tetto del fee rate resta in attesa, visibile, e non
|
||||
viene abbandonata ([ADR-51](adr/ADR-51-dubbio-liberano-mai-fondi.md)). Il docstring di `bump_fee` cita ancora come
|
||||
esempio «una scommessa senza resto», caso che dopo B-62 non esiste più.
|
||||
riducibile — il resto verso il mittente per scommesse e prelievi, l'uscita
|
||||
di riserva per il pagamento ([RND-38](ciclo-di-vita-del-round.md#4--pagamento), B-79).
|
||||
Non c'è il ripiego «aggiungi un'altra moneta» né il CPFP. Ogni aumento costa
|
||||
almeno 1 sat/vB sull'intera dimensione della transazione (141 sat per una
|
||||
transazione con un ingresso e due uscite) e si toglie da quell'uscita; se
|
||||
quanto resta sarebbe sotto la soglia di polvere l'uscita viene eliminata e
|
||||
il suo valore va in commissione, e quella sostituzione è l'ultima (B-87,
|
||||
[ADR-19](adr/ADR-19-ogni-transazione-utente-conserva-uscita-resto.md)); se
|
||||
nemmeno l'intera uscita raggiunge l'aumento minimo, o non esiste, `bump_fee`
|
||||
solleva `RbfError`.
|
||||
- *Impatto:* con la rete congestionata una transazione a 1 sat/vB che ha
|
||||
esaurito resto o riserva può restare in mempool indefinitamente. Poiché il
|
||||
riconciliatore abbandona solo ciò che il server **non conosce**, una
|
||||
transazione ferma ma presente in mempool non viene mai abbandonata: una
|
||||
scommessa così blocca il round in `closing`, un pagamento così lo blocca
|
||||
in `paying_out`.
|
||||
- *Mitigazione attuale:* la riserva del pagamento è dimensionata per circa
|
||||
10 sat/vB; resto minimo garantito sulle transazioni utente; tetto al fee
|
||||
rate (`MAX_FEE_RATE_SAT_VB`); ogni accelerazione impossibile o rifiutata
|
||||
scrive `rbf_bump_failed` (una volta per transazione e motivo); abbandono
|
||||
dopo 6 ore per ciò che sparisce dalla rete; ritentativo automatico del
|
||||
pagamento dopo un abbandono.
|
||||
- *Stato:* accettato dopo B-79 e B-87: una transazione che ha esaurito resto
|
||||
o riserva e non conferma nemmeno al tetto del fee rate resta in attesa,
|
||||
visibile, e non viene abbandonata ([ADR-51](adr/ADR-51-dubbio-liberano-mai-fondi.md)).
|
||||
|
||||
*Codice:* `app/tx/broadcast.py:bump_fee` · `app/wallet/psbt_builder.py:build_payout_transaction` · `app/tx/reconcile.py:reconcile_once`
|
||||
|
||||
@@ -95,7 +88,7 @@ implementato il [piano delle correzioni](piano-correzioni.md).
|
||||
nuovo round si apre nel frattempo.
|
||||
- *Mitigazione attuale:* lo stato è visibile (`closing`) e il pannello
|
||||
«Transazioni pendenti» mostra la scommessa che trattiene il round.
|
||||
- *Stato:* B-78 e B-77 chiusi; resta da chiudere B-87 (resto minimo), e per scelta l'assenza di un limite di tempo.
|
||||
- *Stato:* B-78, B-77 e B-87 chiusi; resta per scelta l'assenza di un limite di tempo.
|
||||
- *Per chiuderlo:* con B-78 l'attesa finisce quando la scommessa conferma
|
||||
(una qualsiasi delle sue versioni, B-77) o quando c'è la prova che non
|
||||
confermerà mai ([ADR-51](adr/ADR-51-dubbio-liberano-mai-fondi.md)), non dopo un tempo fisso; con B-87 la scommessa
|
||||
|
||||
+12
-12
@@ -608,15 +608,18 @@ con `docker compose logs app` ([architettura.md](architettura.md) ARC-09).
|
||||
### RBF impossibile
|
||||
|
||||
- **[OPS-17]**
|
||||
**Sintomi.** Nel log, ogni 30 secondi per la stessa riga,
|
||||
`could not bump pending_transaction N` con un `RbfError`: "no change output
|
||||
large enough to absorb a fee bump" oppure "already at the maximum fee rate".
|
||||
Nessuna riga di audit. `attempt_count` smette di salire. Un aumento che la
|
||||
rete rifiuta (per esempio perché il resto scenderebbe sotto la soglia di
|
||||
polvere) compare invece come errore di invio nello stesso messaggio.
|
||||
**Causa.** L'RBF riduce solo il resto che torna al mittente; se il resto non
|
||||
basta a coprire l'aumento, o la commissione è già al massimo (10.000 sat/vB),
|
||||
non si può fare. Un pagamento ha un'uscita di riserva
|
||||
**Sintomi.** Una riga `rbf_bump_failed` nel registro di audit (sezione
|
||||
Audit log del pannello, con `pending_transaction_id`, `txid` e `reason`):
|
||||
`change_too_small`, `max_fee_rate` o `replacement_rejected`. Se ne scrive una
|
||||
sola per transazione e motivo; nel log, ogni 30 secondi, resta
|
||||
`could not bump pending_transaction N`. `attempt_count` smette di salire.
|
||||
**Causa.** L'RBF riduce un'unica uscita, il resto che torna al mittente; se
|
||||
l'aumento la porterebbe sotto la soglia di polvere l'uscita viene eliminata
|
||||
e il suo valore va in commissione, e quella sostituzione è l'ultima
|
||||
(`change_too_small` ai tentativi successivi). Non si può fare nemmeno se
|
||||
l'uscita non esiste o non basta all'aumento minimo, o se la commissione è già
|
||||
al massimo (10.000 sat/vB, `max_fee_rate`); `replacement_rejected` è una
|
||||
sostituzione che la rete ha rifiutato esplicitamente. Un pagamento ha un'uscita di riserva
|
||||
(B-79) che l'aumento riduce; la riserva è dimensionata per arrivare a circa
|
||||
10 sat/vB, oltre la quale (o per un pagamento costruito prima di B-79, che
|
||||
non ce l'ha) la transazione non si può accelerare.
|
||||
@@ -628,9 +631,6 @@ con `docker compose logs app` ([architettura.md](architettura.md) ARC-09).
|
||||
([OPS-23]); il sistema accrediterà l'uscita della nuova transazione come un
|
||||
normale deposito. Per un pagamento non c'è un'alternativa supportata: la
|
||||
chiave del montepremi non è esportabile ([OPS-24]).
|
||||
Dopo B-87 un aumento che lascerebbe un resto sotto la soglia di polvere
|
||||
toglie il resto invece di fallire, e ogni fallimento scrive
|
||||
`rbf_bump_failed`.
|
||||
*Codice:* `app/tx/broadcast.py:bump_fee`, `app/tx/broadcast.py:RbfBumper._tick` ·
|
||||
*Test:* `tests/unit/test_broadcast.py`
|
||||
|
||||
|
||||
+3
-3
@@ -235,7 +235,7 @@ cifrava di nuovo il file sbagliato (vedi [operativita.md](operativita.md)).
|
||||
| B-84 | Il quorum può ridursi a un solo server o a nessuno senza avvisi; certificati TLS non verificati | Alta | *da registrare* | `test_electrum_client.py`, `test_electrum_listener.py` | ELC, SEC |
|
||||
| B-85 | Le riorganizzazioni della catena non vengono né seguite né segnalate | Alta | *da registrare* | `test_electrum_listener.py` | ELC, RND |
|
||||
| B-86 | Un server connesso ma fermo non viene mai sostituito | Alta | *da registrare* | `test_electrum_listener.py` | ELC, OPS |
|
||||
| B-87 | L'RBF può lasciare un resto sotto la soglia di dust | Alta | **aperto** | — | TX |
|
||||
| B-87 | L'RBF può lasciare un resto sotto la soglia di dust | Alta | *da registrare* | `test_rbf_dust.py`, `test_broadcast.py` | TX |
|
||||
| B-88 | Le transazioni SQLite non sono quelle che il codice presuppone; `synchronous=NORMAL` può perdere gli ultimi commit | Alta | *da registrare* | `test_sqlite_transactions.py`, `test_db_base.py` | DAT, ARC |
|
||||
| B-89 | Problemi della chiave rilevati solo al primo uso; gli script accettano qualunque xprv e scrivono file leggibili da tutti | Alta | **aperto** | — | SEC, OPS |
|
||||
| B-90 | Il ripristino di un backup riapre round già pagati e riassegna indici di derivazione | Alta | **aperto** | — | OPS, REG |
|
||||
@@ -252,9 +252,9 @@ cifrava di nuovo il file sbagliato (vedi [operativita.md](operativita.md)).
|
||||
|
||||
- **Corretti:** B-01 … B-70, tranne B-16, che è chiuso nella sostanza (il
|
||||
crash è eliminato e `/guida` serve un segnaposto) ma lascia la guida vera
|
||||
come limite accettato; dalla revisione del 2026-09-28: B-88, B-75, B-97, B-80, B-84, B-76, B-77, B-78, B-83, B-74, B-85, B-86, B-73, B-81, B-79, B-82.
|
||||
come limite accettato; dalla revisione del 2026-09-28: B-88, B-75, B-97, B-80, B-84, B-76, B-77, B-78, B-83, B-74, B-85, B-86, B-73, B-81, B-79, B-82, B-87.
|
||||
- **Aperti:** B-71, B-72 (gravità bassa, operativi o di documentazione) e
|
||||
B-73 … B-98 dalla revisione del 2026-09-28 tranne i corretti (0 critici,
|
||||
4 alti, 6 medi), da implementare nell'ordine di
|
||||
3 alti, 6 medi), da implementare nell'ordine di
|
||||
[piano-correzioni.md](piano-correzioni.md).
|
||||
- **Prossimo numero libero:** `B-99`.
|
||||
@@ -243,11 +243,7 @@ sostituibilità fin dal primo invio.
|
||||
partita ([TX-17]): finché almeno un server la tiene in mempool non viene
|
||||
mai abbandonata.
|
||||
*Codice:* `app/tx/broadcast.py:bump_fee`, `app/tx/broadcast.py:_find_change_output` ·
|
||||
*Test:* `tests/unit/test_broadcast.py`
|
||||
*Stato:* da implementare (B-87) · *Oggi:* il pagamento si accelera già
|
||||
dall'uscita di riserva (B-79), ma per ogni transazione basta che l'uscita
|
||||
superi l'aumento: un resto di 294 sat diventa 153 sat, sotto la soglia di
|
||||
dust, e la rete rifiuta la sostituzione a ogni giro.
|
||||
*Test:* `tests/unit/test_broadcast.py`, `tests/unit/test_rbf_dust.py`
|
||||
- **[TX-12]** **Prima si scrive la sostituzione, poi si invia.** La
|
||||
sostituzione firmata viene registrata come candidata in
|
||||
`pending_transaction_txids` (txid e transazione completa, [TX-19]) e
|
||||
@@ -282,10 +278,8 @@ sostituibilità fin dal primo invio.
|
||||
tentativo che fallisce di nuovo per lo stesso motivo sullo stesso txid va
|
||||
solo nei log, così una transazione non accelerabile non riempie il registro
|
||||
con una riga ogni 30 secondi.
|
||||
*Codice:* `app/tx/broadcast.py:RbfBumper._tick` ·
|
||||
*Test:* —
|
||||
*Stato:* da implementare (B-87) · *Oggi:* l'errore finisce solo nei log
|
||||
dell'applicazione, invisibile da `/admin`.
|
||||
*Codice:* `app/tx/broadcast.py:RbfBumper._tick`, `app/tx/broadcast.py:RbfBumper._record_failure` ·
|
||||
*Test:* `tests/unit/test_rbf_dust.py`
|
||||
|
||||
Il resto minimo di scommesse e prelievi è di 294 sat
|
||||
([BET-14](scommesse-e-prelievi.md#cosa-succede),
|
||||
|
||||
Reference in new issue
Block a user