1// PKGPATH: gno.land/r/demo/grc20subrealm23// A frame-relative teller must keep working when the token's OWN realm4// operates under an identity minted by its own cur.Sub(). The sub's synthesized5// pkgpath is "<host>#vault", which is not origRealm verbatim, so a raw string6// comparison would refuse the token's own realm — a false positive that would7// break the one property the home binding promises unconditionally.8package grc20subrealm910import (11 "chain"1213 "gno.land/p/nt/grc20/v0"14)1516var (17 token *grc20.Token18 ledger *grc20.PrivateLedger19 teller grc20.Teller20)2122func init(cur realm) {23 token, ledger = grc20.NewToken("SubRealm", "SUBR", 4, 0, cur)24 teller = ledger.CallerTeller()25}2627func main(cur realm) {28 payer := cur.Previous().Address() // whom the frame-relative teller debits29 bob := chain.PackageAddress("bob")30 ledger.Mint(payer, 1_000)3132 // Control: the primary identity moves the caller's funds.33 if err := teller.Transfer(0, cur, bob, 100); err != nil {34 panic("primary identity rejected: " + err.Error())35 }3637 // Same realm, same teller, under this realm's own "vault" sub identity.38 if err := teller.Transfer(0, cur.Sub("vault"), bob, 100); err != nil {39 panic("own sub identity rejected: " + err.Error())40 }4142 if got := token.BalanceOf(bob); got != 200 {43 panic("unexpected bob balance")44 }4546 // The mirror image: a token CREATED from a sub frame must still be usable47 // from its host realm. origRealm drops the subpath at construction, so the48 // token belongs to the host rather than being stranded in the sub.49 subTok, subLedger := grc20.NewToken("FromSub", "FSUB", 4, 1, cur.Sub("vault"))50 subTeller := subLedger.CallerTeller()51 subLedger.Mint(payer, 500)52 if err := subTeller.Transfer(0, cur, bob, 50); err != nil {53 panic("host realm rejected for a sub-created token: " + err.Error())54 }55 if got := subTok.BalanceOf(bob); got != 50 {56 panic("unexpected bob balance on the sub-created token")57 }5859 println("ok")60}6162// Output:63// ok64Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.