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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

moultest_test.gno

7.82 Kb · 207 lines
  1package moultest
  2
  3import (
  4	"chain"
  5	"strings"
  6	"testing"
  7
  8	"gno.land/p/nt/testutils/v0"
  9	"gno.land/p/nt/uassert/v0"
 10)
 11
 12// testing.SetRealm governs only the crossing calls made from the frame that
 13// called it, so every account switch below is written inline in the test body
 14// rather than in a helper.
 15
 16func TestDenom(t *testing.T) {
 17	// The denom is what a wallet, an explorer and a -send flag all type, and it
 18	// is immutable once the first coin exists. Pin the literal: deriving it from
 19	// Path would restate the code rather than check it.
 20	uassert.Equal(t, "/gno.land/r/nym-moultest123/x/moultest/v0:moultest", Denom)
 21}
 22
 23func TestClaimIssuesRealCoins(cur realm, t *testing.T) {
 24	alice := testutils.TestAddress("mt-alice")
 25	testing.SetRealm(testing.NewUserRealm(alice))
 26
 27	_, ever := NextClaim(alice)
 28	uassert.False(t, ever, "no claim recorded before the first one")
 29	uassert.Equal(t, int64(0), BalanceOf(alice))
 30
 31	before := Circulating()
 32	got := Claim(cross(cur))
 33
 34	uassert.Equal(t, ClaimAmount, got)
 35	// The balance comes from the bank, not from realm storage: nothing in this
 36	// realm records who holds what.
 37	uassert.Equal(t, ClaimAmount, BalanceOf(alice))
 38	uassert.Equal(t, before+ClaimAmount, Circulating())
 39	uassert.Equal(t, ClaimAmount, ClaimedBy(alice))
 40
 41	next, ever := NextClaim(alice)
 42	uassert.True(t, ever, "a cooldown is recorded")
 43	uassert.Equal(t, ClaimEvery, next-123, "first test block is 123, so the cooldown lands there")
 44}
 45
 46func TestClaimCooldown(cur realm, t *testing.T) {
 47	bob := testutils.TestAddress("mt-bob")
 48	testing.SetRealm(testing.NewUserRealm(bob))
 49
 50	Claim(cross(cur))
 51	uassert.AbortsContains(t, cur, "too soon", func() { Claim(cross(cur)) })
 52
 53	testing.SkipHeights(ClaimEvery - 1)
 54	uassert.AbortsContains(t, cur, "too soon", func() { Claim(cross(cur)) })
 55
 56	testing.SkipHeights(1)
 57	Claim(cross(cur))
 58	uassert.Equal(t, 2*ClaimAmount, BalanceOf(bob))
 59}
 60
 61func TestAccountCap(cur realm, t *testing.T) {
 62	carol := testutils.TestAddress("mt-carol")
 63	testing.SetRealm(testing.NewUserRealm(carol))
 64
 65	for ClaimedBy(carol)+ClaimAmount <= MaxPerAccount {
 66		Claim(cross(cur))
 67		testing.SkipHeights(ClaimEvery)
 68	}
 69	uassert.Equal(t, MaxPerAccount, ClaimedBy(carol))
 70	uassert.AbortsContains(t, cur, "account cap reached", func() { Claim(cross(cur)) })
 71
 72	// Waiting does not help: the cooldown is not what stopped it.
 73	testing.SkipHeights(ClaimEvery * 10)
 74	uassert.AbortsContains(t, cur, "account cap reached", func() { Claim(cross(cur)) })
 75}
 76
 77func TestBurnIsScopedToTheCaller(cur realm, t *testing.T) {
 78	dave := testutils.TestAddress("mt-dave")
 79	erin := testutils.TestAddress("mt-erin")
 80
 81	testing.SetRealm(testing.NewUserRealm(erin))
 82	Claim(cross(cur))
 83	erinBefore := BalanceOf(erin)
 84
 85	testing.SetRealm(testing.NewUserRealm(dave))
 86	Claim(cross(cur))
 87
 88	issuedBefore, burnedBefore, circBefore := Issued(), Burned(), Circulating()
 89	claimedBefore := ClaimedBy(dave)
 90
 91	Burn(cross(cur), 400)
 92
 93	uassert.Equal(t, ClaimAmount-400, BalanceOf(dave))
 94	uassert.Equal(t, circBefore-400, Circulating(), "burning destroys the coin, it is not moved")
 95	uassert.Equal(t, burnedBefore+400, Burned())
 96	// Issuance is monotonic on purpose: if burning gave cap headroom back,
 97	// claim-burn-claim would be an unlimited faucet.
 98	uassert.Equal(t, issuedBefore, Issued())
 99	uassert.Equal(t, claimedBefore, ClaimedBy(dave))
100	// Burn takes no address, so erin cannot be reached from dave's call.
101	uassert.Equal(t, erinBefore, BalanceOf(erin))
102
103	uassert.AbortsContains(t, cur, "cannot burn", func() { Burn(cross(cur), 1_000_000) })
104	uassert.AbortsContains(t, cur, "positive amount", func() { Burn(cross(cur), 0) })
105	uassert.AbortsContains(t, cur, "positive amount", func() { Burn(cross(cur), -5) })
106}
107
108func TestTipRidesTheEnvelope(cur realm, t *testing.T) {
109	frank := testutils.TestAddress("mt-frank")
110	grace := testutils.TestAddress("mt-grace")
111
112	// On chain the -send envelope is credited to this realm's address before
113	// the function runs. The test harness has no bank-send primitive, so the
114	// credit is issued directly here; SetOriginSend is what the banker checks
115	// against, and it is the half that bounds what Tip may spend.
116	realmAddr := chain.PackageAddress(Path)
117	envelope := chain.NewCoins(chain.NewCoin(Denom, 250))
118	testing.IssueCoins(realmAddr, envelope)
119	// Unrelated coins already sitting at the realm's address. A RealmSend
120	// banker could spend these; the OriginSend one may not, and that is the
121	// property being pinned.
122	testing.IssueCoins(realmAddr, chain.NewCoins(chain.NewCoin(Denom, 5_000)))
123	realmBefore := BalanceOf(realmAddr)
124
125	testing.SetRealm(testing.NewUserRealm(frank))
126	testing.SetOriginSend(envelope)
127	sent := Tip(cross(cur), grace, "nice work")
128
129	uassert.Equal(t, int64(250), sent)
130	uassert.Equal(t, int64(250), BalanceOf(grace), "the tip landed on the recipient")
131	uassert.Equal(t, realmBefore-250, BalanceOf(realmAddr),
132		"exactly the envelope left the realm, and nothing else it was holding")
133	uassert.Equal(t, 1, len(tips))
134	uassert.Equal(t, "nice work", tips[0].note)
135
136	testing.SetOriginSend(nil)
137}
138
139func TestTipRefusals(cur realm, t *testing.T) {
140	heidi := testutils.TestAddress("mt-heidi")
141	ivan := testutils.TestAddress("mt-ivan")
142
143	testing.SetRealm(testing.NewUserRealm(heidi))
144	testing.SetOriginSend(nil)
145	uassert.AbortsContains(t, cur, "attach moultest", func() { Tip(cross(cur), ivan, "hi") })
146
147	envelope := chain.NewCoins(chain.NewCoin(Denom, 10))
148	testing.IssueCoins(chain.PackageAddress(Path), envelope)
149	testing.SetOriginSend(envelope)
150	uassert.AbortsContains(t, cur, "tip somebody else", func() { Tip(cross(cur), heidi, "me") })
151	uassert.AbortsContains(t, cur, "valid address", func() { Tip(cross(cur), "nope", "hi") })
152	uassert.AbortsContains(t, cur, "note is", func() {
153		Tip(cross(cur), ivan, strings.Repeat("x", MaxNote+1))
154	})
155
156	testing.SetOriginSend(nil)
157}
158
159func TestSupplyCap(cur realm, t *testing.T) {
160	// Fill the remaining supply with fresh accounts, each capped at
161	// MaxPerAccount, then check that the next one is refused. Issuance carries
162	// across tests, so the loop starts from whatever is left rather than from
163	// MaxSupply.
164	names := []string{"cap-a", "cap-b", "cap-c", "cap-d", "cap-e", "cap-f",
165		"cap-g", "cap-h", "cap-i", "cap-j", "cap-k", "cap-l"}
166	for _, name := range names {
167		if Issued()+ClaimAmount > MaxSupply {
168			break
169		}
170		who := testutils.TestAddress(name)
171		testing.SetRealm(testing.NewUserRealm(who))
172		for ClaimedBy(who)+ClaimAmount <= MaxPerAccount && Issued()+ClaimAmount <= MaxSupply {
173			Claim(cross(cur))
174			testing.SkipHeights(ClaimEvery)
175		}
176	}
177	uassert.Equal(t, MaxSupply, Issued(), "the accounts above exhaust the supply exactly")
178
179	late := testutils.TestAddress("cap-late")
180	testing.SetRealm(testing.NewUserRealm(late))
181	uassert.AbortsContains(t, cur, "supply cap reached", func() { Claim(cross(cur)) })
182
183	// Burning does not reopen the faucet either: circulating drops, issued does
184	// not, and the cap is on issued.
185	testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("cap-a")))
186	Burn(cross(cur), 500)
187	uassert.Equal(t, MaxSupply, Issued())
188	testing.SetRealm(testing.NewUserRealm(late))
189	uassert.AbortsContains(t, cur, "supply cap reached", func() { Claim(cross(cur)) })
190}
191
192func TestRender(t *testing.T) {
193	index := Render("")
194	uassert.True(t, strings.Contains(index, "# moultest"), "heading:\n"+index)
195	uassert.True(t, strings.Contains(index, Denom), "the denom is on the page")
196	uassert.True(t, strings.Contains(index, "| issued, ever |"), "supply table:\n"+index)
197	uassert.True(t, strings.Contains(index, "nice work"), "the tip board is shown:\n"+index)
198
199	frank := testutils.TestAddress("mt-frank")
200	acct := Render(frank.String())
201	uassert.True(t, strings.Contains(acct, frank.String()), "the account section names it:\n"+acct)
202	uassert.True(t, strings.Contains(acct, "claimed for life"), acct)
203
204	// A path that is not an address renders the index without an account block.
205	uassert.False(t, strings.Contains(Render("not-an-address"), "claimed for life"),
206		"a junk path adds no account section")
207}