Search Apps Documentation Source Content File Folder Download Copy Actions Download

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)