← Back to Realms

Realm

gno.land/r/moul/x/across/v0

Overview

Realm Path
gno.land/r/moul/x/across/v0
Exported Functions
3
State Entries
5
Source Files
3
Total Package Entries
10

Exported Functions

3 exported functions

State

5 state entries

Source Code

FILES
across.gno
go
1// Package across reads one address across fifteen other realms that are
2// already live, and renders everything they will say about it on one page.
3//
4// It is a composability demo with a working product hiding inside it. The
5// realms it reads were written months apart, by nobody coordinating, and none
6// of them knows this one exists. Not a line of them changed to make this
7// possible: the only requirement any of them had to meet was NOT declaring
8// `private = true`, which is what lets another realm import it at all.
9//
10// # Why this realm holds no state and extracts no library
11//
12// Every other realm here splits into a pure `p/` and a thin `r/`. This one
13// cannot, and that is the point: its entire content is the wiring. Fifteen
14// import lines, one call each, and a table. Extract a library and what is left
15// on both sides is empty.
16//
17// # What it measures, besides balances
18//
19// The signatures below are the honest half of the demo. Eight of these realms
20// hold a per-address balance and they agree on nothing:
21//
22//	erc20, vestoken, wrapped     BalanceOf(address) uint64
23//	pairs/aaa, pairs/bbb         BalanceOf(address) int64
24//	grc20faucet                  BalanceOf(symbol string, owner address) int64
25//	wikicoin                     BalanceOf(address) uint
26//	dice                         RollsOf(addr string) []int
27//
28// Three integer widths, two signednesses, one that takes the address as a
29// string, one that needs a symbol first. Composition works anyway, because a
30// gno import is a type-checked contract with a permanent artifact behind it and
31// not a call convention anyone has to agree on in advance. It just costs one
32// hand-written adapter per source, which is what the report function is.
33//
34// # The two sources that could not be read
35//
36//   - r/moul/x/amm/v0 exports SharesOf(keyA, keyB string, owner address), and
37//     it routes through mustPool, which PANICS when the pool does not exist.
38//     A getter that panics is not composable: fifteen sources on one page means
39//     one panicking source takes the whole page down, and a wrapper cannot
40//     recover, because recover() does not catch a cross-realm abort. So amm
41//     contributes PoolCount() to the index and nothing to a report.
42//   - r/moul/demo/vault/v0 exports MyBalance() with no address parameter. It
43//     answers for whoever is calling, which from here is this realm, so the
44//     value is structurally unreadable from outside.
45//
46// Neither is a bug in those realms. Both are what a getter looks like when
47// nobody has tried to call it from another realm yet.
48package across
49
50import (
51	"strconv"
52	"strings"
53
54	"gno.land/p/moul/kit/ui/v0"
55
56	"gno.land/r/moul/demo/wikicoin/v0"
57	"gno.land/r/moul/reactions/v0"
58	"gno.land/r/moul/x/amm/v0"
59	"gno.land/r/moul/x/daily/dice/v0"
60	"gno.land/r/moul/x/daily/erc20/v0"
61	"gno.land/r/moul/x/daily/lottery/v0"
62	"gno.land/r/moul/x/daily/ratelimitdemo/v0"
63	"gno.land/r/moul/x/daily/staking/v0"
64	"gno.land/r/moul/x/daily/streak/v0"
65	"gno.land/r/moul/x/daily/vestoken/v0"
66	"gno.land/r/moul/x/daily/wrapped/v0"
67	"gno.land/r/moul/x/grc20faucet/v0"
68	"gno.land/r/moul/x/pairs/aaa/v0"
69	"gno.land/r/moul/x/pairs/aaabbb/v0"
70	"gno.land/r/moul/x/pairs/bbb/v0"
71)
72
73// reactionPage is the page key handed to r/moul/reactions. Reactions are keyed
74// on an arbitrary page string rather than on a realm, so a reader of this
75// report is asked about the same page /u/moul shows.
76const reactionPage = "gno.land/r/moul/home"
77
78// Self is this realm's own package path, exported so a caller can build a link
79// back without hardcoding the version.
80const Self = "gno.land/r/moul/x/across/v0"
81
82// A fact is one answer from one source realm about one address.
83//
84// zero is carried separately from value because "0" and "none" are the common
85// answer and the table is worth reading only for the rows that are not that.
86type fact struct {
87	source string // package path, without the gno.land/ prefix
88	what   string
89	value  string
90	zero   bool
91}
92
93// Report collects what every wired source says about who.
94//
95// Every call in here is a plain exported read on another realm: no cur realm,
96// no cross, nothing written. A read with no realm parameter is borrowed rather
97// than entered (AGENTS.md), so none of these realms even observes a caller.
98func Report(who address) []fact {
99	out := []fact{}
100
101	add := func(source, what string, n int64, unit string) {
102		v := strconv.FormatInt(n, 10)
103		if unit != "" {
104			v += " " + unit
105		}
106		out = append(out, fact{source: source, what: what, value: v, zero: n == 0})
107	}
108
109	// Balances. Eight sources, five signatures.
110	add("r/moul/x/daily/erc20/v0", "balance", int64(erc20.BalanceOf(who)), erc20.Symbol())
111	add("r/moul/x/daily/vestoken/v0", "liquid balance", int64(vestoken.BalanceOf(who)), vestoken.Symbol())
112	add("r/moul/x/daily/wrapped/v0", "wrapped balance", int64(wrapped.BalanceOf(who)), "WGNOT")
113	add("r/moul/demo/wikicoin/v0", "balance", int64(wikicoin.BalanceOf(who)), "WIKI")
114	add("r/moul/x/pairs/aaa/v0", "balance", aaa.BalanceOf(who), "AAA")
115	add("r/moul/x/pairs/bbb/v0", "balance", bbb.BalanceOf(who), "BBB")
116	add("r/moul/x/grc20faucet/v0", "balance", grc20faucet.BalanceOf("RED", who), "RED")
117	add("r/moul/x/grc20faucet/v0", "balance", grc20faucet.BalanceOf("BLUE", who), "BLUE")
118
119	// A grant is three numbers, so it does not fit the add helper.
120	total, claimed, claimable := vestoken.GrantOf(who)
121	out = append(out, fact{
122		source: "r/moul/x/daily/vestoken/v0",
123		what:   "vesting grant",
124		value: strconv.FormatUint(total, 10) + " total, " +
125			strconv.FormatUint(claimed, 10) + " claimed, " +
126			strconv.FormatUint(claimable, 10) + " claimable",
127		zero: total == 0,
128	})
129
130	// Positions.
131	add("r/moul/x/pairs/aaabbb/v0", "LP shares", aaabbb.SharesOf(who), "")
132	add("r/moul/x/daily/staking/v0", "staked", int64(staking.StakedOf(who)), "")
133	add("r/moul/x/daily/staking/v0", "unclaimed rewards", int64(staking.Earned(who)), "")
134
135	// Activity.
136	add("r/moul/x/daily/streak/v0", "current streak", int64(streak.Current(who)), "day(s)")
137	add("r/moul/x/daily/streak/v0", "best streak", int64(streak.Best(who)), "day(s)")
138	add("r/moul/x/daily/dice/v0", "dice rolled", int64(len(dice.RollsOf(who.String()))), "")
139	add("r/moul/x/daily/ratelimitdemo/v0", "rate-limit tokens left", int64(ratelimitdemo.Tokens(who)), "")
140
141	entered := "no"
142	if lottery.HasEntered(who) {
143		entered = "yes, round " + strconv.Itoa(lottery.CurrentRound())
144	}
145	out = append(out, fact{
146		source: "r/moul/x/daily/lottery/v0",
147		what:   "entered the lottery",
148		value:  entered,
149		zero:   !lottery.HasEntered(who),
150	})
151
152	// reactions answers with a palette key, already validated at write time, so
153	// it never carries caller markdown into this table.
154	react := reactions.ReactionOf(reactionPage, who)
155	shown := react
156	if shown == "" {
157		shown = "none"
158	}
159	out = append(out, fact{
160		source: "r/moul/reactions/v0",
161		what:   "reaction on " + reactionPage,
162		value:  shown,
163		zero:   react == "",
164	})
165
166	return out
167}
168
169// sourceRealms is every realm this one imports for its data, in import order.
170// It is the single place the count comes from: the index table has one row per
171// entry and TestSourcesCoverReport checks that Report names nothing else.
172//
173// Fifteen entries, which is the number the prose says. TestSourceCount pins it.
174var sourceRealms = []string{
175	"r/moul/x/daily/erc20/v0",
176	"r/moul/x/daily/vestoken/v0",
177	"r/moul/x/daily/wrapped/v0",
178	"r/moul/demo/wikicoin/v0",
179	"r/moul/x/pairs/aaa/v0",
180	"r/moul/x/pairs/bbb/v0",
181	"r/moul/x/grc20faucet/v0",
182	"r/moul/x/pairs/aaabbb/v0",
183	"r/moul/x/amm/v0",
184	"r/moul/x/daily/staking/v0",
185	"r/moul/x/daily/streak/v0",
186	"r/moul/x/daily/dice/v0",
187	"r/moul/x/daily/lottery/v0",
188	"r/moul/x/daily/ratelimitdemo/v0",
189	"r/moul/reactions/v0",
190}
191
192// Sources reports how many realms this one reads.
193func Sources() int { return len(sourceRealms) }
194
195func Render(path string) string {
196	if path == "" {
197		return renderIndex()
198	}
199	addr := address(path)
200	if !addr.IsValid() {
201		return "# across\n\n" + ui.Empty(ui.Inline(ui.Short(path))+" is not a valid address.") +
202			"\n[back to the index](/r/moul/x/across/v0)\n"
203	}
204	return renderAddress(addr)
205}
206
207func renderAddress(who address) string {
208	var b strings.Builder
209	b.WriteString("# across: " + ui.AddrFull(who) + "\n\n")
210	b.WriteString("What " + strconv.Itoa(Sources()) + " independently deployed realms say about this address. ")
211	b.WriteString("None of them was changed to answer.\n\n")
212
213	facts := Report(who)
214
215	live := ui.NewTable("source", "fact", "value")
216	quiet := 0
217	for _, f := range facts {
218		if f.zero {
219			quiet++
220			continue
221		}
222		live.Row("[`"+f.source+"`](/"+f.source+")", f.what, f.value)
223	}
224
225	if live.Len() == 0 {
226		b.WriteString(ui.Empty("Every one of the " + strconv.Itoa(len(facts)) +
227			" reads came back empty. This address has never touched any of them."))
228		b.WriteString("\n")
229	} else {
230		b.WriteString("## Answers\n\n")
231		b.WriteString(live.String())
232		b.WriteString("\n")
233		b.WriteString(strconv.Itoa(quiet) + " of " + strconv.Itoa(len(facts)) +
234			" reads came back empty and are hidden.\n\n")
235	}
236
237	b.WriteString("[back to the index](/r/moul/x/across/v0)\n")
238	return b.String()
239}
240
241func renderIndex() string {
242	var b strings.Builder
243	b.WriteString("# across\n\n")
244	b.WriteString("One address, read across " + strconv.Itoa(Sources()) + " realms that are already on chain.\n\n")
245	b.WriteString("Open `/r/moul/x/across/v0:<address>` to get the report. ")
246	b.WriteString("Example: [/r/moul/x/across/v0:" + exampleAddr + "](/r/moul/x/across/v0:" + exampleAddr + ").\n\n")
247
248	b.WriteString("## Why this realm exists\n\n")
249	b.WriteString("A gno realm that does not declare `private = true` can be imported by any ")
250	b.WriteString("other realm, forever, at a path that can never be replaced. That makes every ")
251	b.WriteString("exported read on it a permanent public API. This realm is what happens when ")
252	b.WriteString("somebody actually uses " + strconv.Itoa(Sources()) + " of them at once.\n\n")
253	b.WriteString("Nothing here was negotiated. No registry, no interface, no shared base ")
254	b.WriteString("package, no version handshake, and no change to any source realm.\n\n")
255
256	b.WriteString("## The sources, and what each one is showing right now\n\n")
257	t := ui.NewTable("realm", "global reading")
258	t.Row("[`r/moul/x/daily/erc20/v0`](/r/moul/x/daily/erc20/v0)",
259		erc20.Symbol()+" supply "+strconv.FormatUint(erc20.TotalSupply(), 10))
260	t.Row("[`r/moul/x/daily/vestoken/v0`](/r/moul/x/daily/vestoken/v0)",
261		vestoken.Symbol()+" supply "+strconv.FormatUint(vestoken.TotalSupply(), 10))
262	t.Row("[`r/moul/x/daily/wrapped/v0`](/r/moul/x/daily/wrapped/v0)",
263		"wrapped supply "+strconv.FormatUint(wrapped.TotalSupply(), 10))
264	t.Row("[`r/moul/demo/wikicoin/v0`](/r/moul/demo/wikicoin/v0)", "per-address balances only")
265	t.Row("[`r/moul/x/pairs/aaa/v0`](/r/moul/x/pairs/aaa/v0)",
266		"AAA supply "+strconv.FormatInt(aaa.TotalSupply(), 10))
267	t.Row("[`r/moul/x/pairs/bbb/v0`](/r/moul/x/pairs/bbb/v0)",
268		"BBB supply "+strconv.FormatInt(bbb.TotalSupply(), 10))
269	t.Row("[`r/moul/x/grc20faucet/v0`](/r/moul/x/grc20faucet/v0)",
270		"RED supply "+strconv.FormatInt(grc20faucet.TotalSupply("RED"), 10)+
271			", BLUE supply "+strconv.FormatInt(grc20faucet.TotalSupply("BLUE"), 10))
272	t.Row("[`r/moul/x/pairs/aaabbb/v0`](/r/moul/x/pairs/aaabbb/v0)",
273		"LP shares "+strconv.FormatInt(aaabbb.TotalShares(), 10))
274	t.Row("[`r/moul/x/amm/v0`](/r/moul/x/amm/v0)",
275		strconv.Itoa(amm.PoolCount())+" pool(s), index only (see below)")
276	t.Row("[`r/moul/x/daily/staking/v0`](/r/moul/x/daily/staking/v0)", "per-address stake and rewards")
277	t.Row("[`r/moul/x/daily/streak/v0`](/r/moul/x/daily/streak/v0)",
278		"day "+strconv.FormatInt(streak.Day(), 10))
279	t.Row("[`r/moul/x/daily/dice/v0`](/r/moul/x/daily/dice/v0)",
280		strconv.Itoa(dice.Total())+" roll(s) all time")
281	t.Row("[`r/moul/x/daily/lottery/v0`](/r/moul/x/daily/lottery/v0)",
282		"round "+strconv.Itoa(lottery.CurrentRound())+", "+
283			strconv.Itoa(lottery.NumEntrants())+" entrant(s)")
284	t.Row("[`r/moul/x/daily/ratelimitdemo/v0`](/r/moul/x/daily/ratelimitdemo/v0)", "per-address bucket")
285	t.Row("[`r/moul/reactions/v0`](/r/moul/reactions/v0)",
286		strconv.Itoa(reactions.Pages())+" page(s) reacted to")
287	b.WriteString(t.String())
288	b.WriteString("\n")
289
290	b.WriteString("## What it cost\n\n")
291	b.WriteString("Eight of these hold a per-address balance, and they share no signature: ")
292	b.WriteString("`uint64` three times, `int64` twice, `uint` once, one that wants a symbol ")
293	b.WriteString("before the address, one that wants the address as a `string`. Every source ")
294	b.WriteString("therefore needs its own adapter line. That is the whole cost, and it is paid ")
295	b.WriteString("once by the reader rather than up front by fifteen authors.\n\n")
296
297	b.WriteString("## The two that could not be read\n\n")
298	b.WriteString("- `r/moul/x/amm/v0` routes `SharesOf` through a helper that panics on an ")
299	b.WriteString("unknown pool. One panicking source takes down a page built from " +
300		strconv.Itoa(Sources()) + ", and ")
301	b.WriteString("`recover()` does not catch a cross-realm abort, so only its `PoolCount()` is ")
302	b.WriteString("safe to call from here.\n")
303	b.WriteString("- `r/moul/demo/vault/v0` exports `MyBalance()` with no address parameter. It ")
304	b.WriteString("answers for its caller, which from here is this realm.\n\n")
305	b.WriteString("Neither is a bug. Both are what a getter looks like before anyone has tried ")
306	b.WriteString("to call it from another realm.\n")
307
308	return b.String()
309}
310
311// exampleAddr is moul's address, used only to give the index a link that
312// resolves to a real report instead of an empty one.
313const exampleAddr = "g1manfred47kzduec920z88wfr64ylksmdcedlf5"
314

Raw Package Data

Raw JSON data