escrow.gno
2.51 Kb · 74 lines
1package arena
2
3import (
4 "chain"
5 "chain/banker"
6)
7
8// The money of the realm goes through the four functions below and nowhere
9// else.
10//
11// escrowed is what the realm owes: the stakes of every lobby and of every
12// running round, in ugnot. It goes up in hold, when a player enters, and
13// down in release, before coins leave. The balance of the realm's address is
14// what it has. The rule of this file is
15//
16// balance >= escrowed, and balance == escrowed unless someone gave coins away
17//
18// Coins can only come in through Enter: the chain refuses a call that
19// attaches coins to a function that does not read them. Someone can still
20// send coins straight to the realm's address with a bank transfer. Such
21// coins are owed to nobody, no function spends them, and they stay there.
22//
23// Every function that moves money ends with assertSolvent. If a mistake in
24// this realm ever made a path send more than it released, the realm would be
25// paying one player with the stake of another: the check turns that into an
26// aborted transaction, which takes the payments back with it.
27
28// payDenom is the only coin the realm deals in.
29const payDenom = "ugnot"
30
31// hold records that the realm received amount in stakes.
32func hold(amount int64) {
33 if amount <= 0 {
34 panic(errEscrow)
35 }
36 escrowed += amount
37}
38
39// release takes amount out of what the realm owes. It is called before the
40// coins are sent, and it panics rather than let the counter go below zero.
41func release(amount int64) {
42 if amount <= 0 || amount > escrowed {
43 panic(errEscrow)
44 }
45 escrowed -= amount
46}
47
48// pay sends amount ugnot from the realm's own balance to an address.
49//
50// A RealmSend banker can spend everything the realm holds, which is why it
51// is built here and only here, from the live cur of the crossing function
52// (rlm), and never kept. The bank aborts the transaction if the realm does
53// not have the coins.
54func pay(_ int, rlm realm, to address, amount int64) {
55 if amount <= 0 {
56 panic(errEscrow)
57 }
58 coins := chain.NewCoins(chain.NewCoin(payDenom, amount))
59 banker.NewBanker(banker.BankerTypeRealmSend, rlm).SendCoins(rlm.Address(), to, coins)
60}
61
62// assertSolvent panics unless the realm holds at least what it owes.
63func assertSolvent(_ int, rlm realm) {
64 if banker.NewReadonlyBanker().GetCoin(rlm.Address(), payDenom) < escrowed {
65 panic(errInsolvent)
66 }
67}
68
69// Escrowed returns what the realm owes to players, in ugnot: the stakes of
70// every lobby and of every running round. The balance of the realm's
71// address is never below it.
72func Escrowed() int64 {
73 return escrowed
74}