Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

types.gno

4.60 Kb · 117 lines
  1package treasury
  2
  3import (
  4	"errors"
  5
  6	"gno.land/p/nt/bptree/list/v0"
  7	"gno.land/p/nt/bptree/v0"
  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// IsCanonicalPayment reports whether p is one of treasury's canonical concrete
 80// Payment impls. Use this at any public entry point that accepts a Payment
 81// from an external caller and shows it to a human before it is processed.
 82//
 83// The immutability the constructors provide is a property of these two types,
 84// not of the interface: a foreign impl's String() says whatever its realm
 85// likes, and no Banker will process it, because Banker.Send type-asserts and
 86// so fails only at execution — after a vote has been spent on it.
 87//
 88// Only the value types are listed, deliberately. Banker.Send asserting
 89// p.(coinsPayment) is what makes this check meaningful, so accepting
 90// *coinsPayment would pass a payment that still fails at execution.
 91//
 92// To add a new canonical type: extend the switch below AND add a regression
 93// test (under filetests/ in this package) that a foreign impl is rejected.
 94//
 95// Mirrors IsCanonicalBanker above.
 96func IsCanonicalPayment(p Payment) bool {
 97	switch p.(type) {
 98	case coinsPayment, grc20Payment:
 99		return true
100	default:
101		return false
102	}
103}
104
105// Balance represents the balance of an asset held by a Banker.
106type Balance struct {
107	Denom  string // The denomination of the asset
108	Amount int64  // The amount of the asset
109}
110
111// Common Banker errors.
112var (
113	ErrCurrentRealmIsNotOwner = errors.New("current realm is not the owner of the banker")
114	ErrNoOwnerProvided        = errors.New("no owner provided")
115	ErrInvalidPaymentType     = errors.New("invalid payment type")
116	ErrSpoofedRealm           = errors.New("rlm does not match the current crossing frame")
117)