Search Apps Documentation Source Content File Folder Download Copy Actions Download

banker_canonical_filetest.gno

1.70 Kb · 57 lines
 1// PKGPATH: gno.land/r/treasury/canonicaltest
 2
 3package canonicaltest
 4
 5import (
 6	"chain"
 7	"chain/banker"
 8
 9	"gno.land/p/nt/treasury/v0"
10)
11
12// evilBanker embeds *treasury.CoinsBanker so it inherits ID/Send/Balances/
13// Address via promotion. If treasury used a sealed-interface marker, this
14// type would satisfy the interface and bypass the gate. The canonical-impl
15// allowlist (IsCanonicalBanker / treasury.New's type switch) rejects it
16// because type assertions are nominal: *evilBanker is not *CoinsBanker.
17type evilBanker struct {
18	*treasury.CoinsBanker
19}
20
21func main(cur realm) {
22	ownerAddr := chain.PackageAddress("gno.land/r/treasury/canonicaltest")
23
24	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	}
29
30	// Verify the helper accepts the canonical impl.
31	if !treasury.IsCanonicalBanker(legit) {
32		panic("canonical *CoinsBanker must pass IsCanonicalBanker")
33	}
34
35	// 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	}
40
41	// 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	}
46
47	// 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	}
52
53	println("canonical allowlist OK")
54}
55
56// Output:
57// canonical allowlist OK