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