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

/p/moul/mygnoscan/v0

Directory · 4 Files
README.md Open

gno.land/p/moul/mygnoscan

Builds links into a mygnoscan block explorer, from inside a realm.

A realm knows things its reader cannot see: which chain it is on, what its own address is, which block it was last written at. Turning any of those into a link means knowing the explorer's route table, and a route table copied into thirty realms is thirty places to fix when a route moves. This is the one place.

 1s := mygnoscan.Default()
 2
 3s.Realm("gno.land/r/moul/home")                 // .../realm/r/moul/home?network=mainnet
 4s.Realm("r/moul/home", mygnoscan.TabSource)     // ...&tab=source
 5s.RealmFunc("r/moul/config", "Set")             // source tab, at one function
 6s.Address(addr)                                 // an account
 7s.Block(runtime.ChainHeight())                  // the block we are in
 8s.Tx(hash)                                      // one transaction, base64 hash
 9s.Proposal(7)                                   // one GovDAO proposal
10s.Page(mygnoscan.PageGas)                       // a list page
11
12s.RealmFooter("gno.land/r/moul/home")           // the markdown line for a Render

Default() is DefaultBase (moul's instance) on whichever network answers for the running chain. New(base) points somewhere else, WithNetwork(id) overrides the network. Nothing here reads chain state beyond ChainDomain, ChainID and ChainHeight, and nothing writes: building a link is free.

For a realm that wants the target to be changeable without a redeploy, read the base from r/moul/config instead of calling Default(): config.Scanner() returns exactly this type, configured.

The routes are measured

Every path was read out of the explorer's own router (route() in its single-page frontend) on 2026-09-22, not inferred from clicking the UI. Two realm tabs that the UI still redirects are deliberately absent because they no longer exist: ?tab=graph (folded into deps) and ?tab=inert (folded into the default tab, and dropped from the URL).

Three things that will bite otherwise

  • An unknown path renders the home page. The explorer's router falls through to home rather than to a 404, so a misspelled route is not visible as an error: the link works and goes somewhere else. That is why the page names are constants and Page is the only door to them.
  • Omitting ?network= is not the same as asking for mainnet. The explorer then answers for every chain it indexes at once, which looks plausible and is wrong. A Scanner on a chain NetworkFor does not know emits no network parameter, so New under gnodev (chain-id dev) produces links to the blend. WithNetwork is how you fix that.
  • The network ids belong to the instance, not to the chain. DefaultBase names mainnet mainnet; the upstream default configuration names the same chain gnoland1. NetworkFor maps chain-ids to what DefaultBase serves, so pointing New at another instance usually means setting WithNetwork too.

Everything here can end up inside a markdown link, so a path carrying ) would close the link early and render the rest as page text. url.PathEscape does not help: ( and ) are legal URL sub-delims and it leaves both alone.

So the two shapes are handled differently, and neither trusts its input:

  • Package paths and page names are refused, not escaped, because escaping their separators would break the route. Realm, RealmFunc, RealmFile, RealmFooter and Page fall back to a list page for anything outside [A-Za-z0-9._/-] or with an empty segment.
  • Hashes, token keys and addresses are escaped with encodeURIComponent semantics, which is what the explorer's decodeURIComponent round-trips. address is a string type and nothing stops a realm casting a caller's input into one, so it gets the same treatment.

Link(text, target) does not escape its text. Pass a constant. A label a caller typed belongs in ui.Inline first.

CurrentRealm and CurrentRealmFooter stack-walk (unsafe.CurrentRealm), so inside a helper borrowed by another realm they name the borrower. That is the right answer for a link and the wrong one for authorisation: never branch on them. A realm calling through a shared config realm should pass its own path explicitly, because the stack seen from in there has the config realm on it.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

⚠️ Disclaimer: provided as-is, without warranty; not security-audited. Full disclaimer: DISCLAIMER.