types.gno
3.54 Kb · 91 lines
1package treasury
2
3import (
4 "errors"
5
6 "gno.land/p/nt/bptree/v0"
7 "gno.land/p/nt/bptree/v0/list"
8 "gno.land/p/nt/mux/v0"
9)
10
11// Treasury is the main structure that holds all bankers and their payment
12// history. It also provides a router for rendering the treasury pages.
13type Treasury struct {
14 bankers *bptree.BPTree // string -> *bankerRecord
15 router *mux.Router
16 realmPath string // owning realm's PkgPath, captured at New() (used for render links)
17}
18
19// bankerRecord holds a Banker and its payment history.
20type bankerRecord struct {
21 banker Banker
22 history list.List // List of Payment.
23}
24
25// Banker is an interface that allows for banking operations.
26//
27// SECURITY: Send takes (int, realm, Payment), so handing a Banker value to
28// untrusted code yields a capability token to whatever Send impl that code
29// dispatches into. The set of canonical impls is closed (*CoinsBanker,
30// *GRC20Banker); any public function that accepts a Banker as a parameter
31// from external callers MUST verify it via IsCanonicalBanker and reject
32// otherwise. treasury.New enforces this for its own intake; future
33// Banker-accepting APIs must do the same. An unexported-marker "seal" does
34// NOT defend against this — see
35// p/test/seal/filetests/z_seal_iface_embedding_filetest.gno.
36//
37// Note that IsCanonicalBanker validates dynamic TYPE only, not captured
38// STATE: a canonical *CoinsBanker constructed via NewCoinsBankerWithOwner
39// with a hostile owner argument passes the allowlist but its read methods
40// (Balances, Address) report data tied to that hostile address. Treasury
41// operators must construct their own bankers and NEVER accept pre-built
42// *Banker values from external realms.
43type Banker interface {
44 ID() string // Get the ID of the banker.
45 Send(int, realm, Payment) error // Send a payment to a recipient.
46 Balances() []Balance // Get the balances of the banker.
47 Address() string // Get the address of the banker to receive payments.
48}
49
50// IsCanonicalBanker reports whether b is one of treasury's canonical
51// concrete Banker impls. Use this at any public entry point in /p/ or /r/
52// that accepts a Banker from an external caller before invoking its methods.
53//
54// Foreign types — including embedding-based wrappers like
55// `type Evil struct { *CoinsBanker }` — are rejected because type assertions
56// are nominal: *Evil is not *CoinsBanker, regardless of method promotion.
57//
58// To add a new canonical type: extend the switch below AND add a regression
59// test (under filetests/ in this package) that an embedded-impl bypass is
60// rejected.
61//
62// Mirrors the precedent of chain/banker.IsCanonical and
63// p/jaekwon/allowancesender's canonical-impl check.
64func IsCanonicalBanker(b Banker) bool {
65 switch b.(type) {
66 case *CoinsBanker, *GRC20Banker:
67 return true
68 default:
69 return false
70 }
71}
72
73// Payment is an interface that allows getting details about a payment.
74type Payment interface {
75 BankerID() string // Get the ID of the banker that can process this payment.
76 String() string // Get a string representation of the payment.
77}
78
79// Balance represents the balance of an asset held by a Banker.
80type Balance struct {
81 Denom string // The denomination of the asset
82 Amount int64 // The amount of the asset
83}
84
85// Common Banker errors.
86var (
87 ErrCurrentRealmIsNotOwner = errors.New("current realm is not the owner of the banker")
88 ErrNoOwnerProvided = errors.New("no owner provided")
89 ErrInvalidPaymentType = errors.New("invalid payment type")
90 ErrSpoofedRealm = errors.New("rlm does not match the current crossing frame")
91)