1// PKGPATH: gno.land/r/treasury/canonicaltest23package canonicaltest45import (6 "chain"7 "chain/banker"89 "gno.land/p/nt/treasury/v0"10)1112// evilBanker embeds *treasury.CoinsBanker so it inherits ID/Send/Balances/13// Address via promotion. If treasury used a sealed-interface marker, this14// type would satisfy the interface and bypass the gate. The canonical-impl15// allowlist (IsCanonicalBanker / treasury.New's type switch) rejects it16// because type assertions are nominal: *evilBanker is not *CoinsBanker.17type evilBanker struct {18 *treasury.CoinsBanker19}2021func main(cur realm) {22 ownerAddr := chain.PackageAddress("gno.land/r/treasury/canonicaltest")2324 inner := banker.NewBanker(banker.BankerTypeRealmSend, cur)25 legit, err := treasury.NewCoinsBankerWithOwner(ownerAddr, inner)26 if err != nil {27 panic("failed to construct canonical banker: " + err.Error())28 }2930 // Verify the helper accepts the canonical impl.31 if !treasury.IsCanonicalBanker(legit) {32 panic("canonical *CoinsBanker must pass IsCanonicalBanker")33 }3435 // Verify the helper rejects an embedded-impl bypass attempt.36 evil := &evilBanker{CoinsBanker: legit}37 if treasury.IsCanonicalBanker(evil) {38 panic("embedded-impl wrapper must NOT pass IsCanonicalBanker")39 }4041 // Verify treasury.New rejects the same bypass attempt.42 _, err = treasury.New([]treasury.Banker{evil}, "")43 if err != treasury.ErrNonCanonicalBankerImpl {44 panic("expected ErrNonCanonicalBankerImpl from treasury.New; got: " + err.Error())45 }4647 // And confirms the canonical banker still works.48 _, err = treasury.New([]treasury.Banker{legit}, "")49 if err != nil {50 panic("canonical banker must be accepted: " + err.Error())51 }5253 println("canonical allowlist OK")54}5556// Output:57// canonical allowlist OK58Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.