Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

bank.gno

3.45 Kb · 116 lines
  1package gnodice
  2
  3import (
  4	"chain"
  5	"chain/banker"
  6	"chain/runtime/unsafe"
  7)
  8
  9// La banque du jeu : son solde est celui de l'adresse du contrat.
 10// Une partie de ce solde est « réservée » : c'est le gain maximal promis aux
 11// parties en cours. Seul le reste (« disponible ») peut couvrir de nouvelles
 12// mises ou être retiré par le propriétaire.
 13
 14// Fund alimente la banque. N'importe qui peut l'appeler en envoyant des GNOT.
 15func Fund(cur realm) {
 16	caller := cur.Previous()
 17	if !caller.IsUserCall() {
 18		panic("gnodice: Fund doit être appelé directement depuis un wallet")
 19	}
 20	sent := unsafe.OriginSend()
 21	if len(sent) != 1 || sent[0].Denom != Denom || sent[0].Amount <= 0 {
 22		panic("gnodice: envoie des GNOT (et uniquement des GNOT) pour alimenter la banque")
 23	}
 24	totalFunded += sent[0].Amount
 25	chain.Emit("BankFunded", "from", caller.Address().String(), "amount", itoa64(sent[0].Amount))
 26}
 27
 28// Withdraw retire des GNOT DISPONIBLES vers le propriétaire. L'argent réservé
 29// aux parties en cours ne peut pas être retiré. amount est en ugnot.
 30func Withdraw(cur realm, amount int64) {
 31	assertOwner(cur)
 32	if amount <= 0 {
 33		panic("gnodice: montant invalide")
 34	}
 35	if amount > available() {
 36		panic("gnodice: montant supérieur au solde disponible (hors réserve des parties en cours)")
 37	}
 38	totalWithdrawn += amount
 39	chain.Emit("BankWithdrawn", "to", owner.String(), "amount", itoa64(amount))
 40	pay(cur, owner, amount) // en dernier
 41	checkLowBankroll()
 42}
 43
 44// Bankroll renvoie le solde total de la banque en ugnot.
 45func Bankroll() int64 {
 46	return banker.NewReadonlyBanker().GetCoin(realmAddr, Denom)
 47}
 48
 49// Reserved renvoie la somme réservée aux parties en cours, en ugnot.
 50func Reserved() int64 {
 51	return reserved
 52}
 53
 54// Available renvoie le solde libre (non réservé), en ugnot.
 55func Available() int64 {
 56	return available()
 57}
 58
 59// MaxCoverableBet renvoie la plus grosse mise (en ugnot) acceptée en ce moment.
 60// Une mise b arrive dans la banque puis réserve 5 x b : il faut donc
 61// disponible + b >= 5 x b, soit b <= disponible / 4.
 62// Renvoie 0 si le jeu est en pause ou si la limite du jour est atteinte.
 63func MaxCoverableBet() int64 {
 64	if paused || dailyLimitReached(now()) {
 65		return 0
 66	}
 67	max := available() / (PayoutMultiplier - 1)
 68	if max > MaxBet {
 69		return MaxBet
 70	}
 71	if max < 0 {
 72		return 0
 73	}
 74	return max
 75}
 76
 77func available() int64 {
 78	return Bankroll() - reserved
 79}
 80
 81// rollDay remet le compteur de gains à zéro quand on change de jour.
 82func rollDay(t int64) {
 83	day := t / 86400
 84	if day != payoutDay {
 85		payoutDay = day
 86		payoutToday = 0
 87	}
 88}
 89
 90func dailyLimitReached(t int64) bool {
 91	if t/86400 != payoutDay {
 92		return false
 93	}
 94	return payoutToday >= dailyPayoutLimit
 95}
 96
 97// recordPayout compte un gain payé. Coupe-circuit : si les gains du jour
 98// dépassent la limite (signe possible d'une attaque ou d'un croupier
 99// compromis), le jeu se met en pause tout seul. Le gain en cours est quand
100// même payé : le joueur a gagné honnêtement.
101func recordPayout(amount int64) {
102	rollDay(now())
103	payoutToday += amount
104	if payoutToday >= dailyPayoutLimit && !paused {
105		paused = true
106		chain.Emit("CircuitBreakerTripped", "payoutToday", itoa64(payoutToday), "limit", itoa64(dailyPayoutLimit))
107		chain.Emit("PauseChanged", "paused", "true", "by", "circuit-breaker")
108	}
109}
110
111// checkLowBankroll émet une alerte quand le solde disponible passe sous le seuil.
112func checkLowBankroll() {
113	if a := available(); a < lowBankroll {
114		chain.Emit("BankrollLow", "available", itoa64(a), "threshold", itoa64(lowBankroll))
115	}
116}