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

example_test.gno

6.32 Kb · 157 lines
  1package authz
  2
  3// Example_basic demonstrates initializing and using a basic member authority
  4func Example_basic(cur realm) {
  5	// Initialize from the EOA caller (e.g. in init(cur realm) of a realm
  6	// being deployed): caller passes the EOA address; the realm itself
  7	// is responsible for verifying the caller is an EOA when needed.
  8	auth := NewWithMembers(cur.Previous().Address())
  9
 10	// Authorize with DoByPrevious, NOT DoByCurrent: the member set holds
 11	// cur.Previous().Address(), and DoByCurrent would present
 12	// cur.Address() -- this realm -- which is never in that set, so the
 13	// action would silently never run. Seeding and authorizing must read
 14	// the SAME side of the frame. Matches the package Quick Start.
 15	if err := auth.DoByPrevious(0, cur, "update_config", func() error {
 16		// config = newValue
 17		return nil
 18	}); err != nil {
 19		panic(err)
 20	}
 21}
 22
 23// Example_addingMembers demonstrates how to add new members to a member authority
 24func Example_addingMembers(cur realm) {
 25	// Seed with Previous(), not Address(): MemberAuthority.AddMember
 26	// derives its principal as rlm.Previous().Address(), so a set holding
 27	// only cur.Address() authorizes nobody and the AddMember below fails.
 28	auth := NewWithMembers(cur.Previous().Address())
 29
 30	// Add a new member to the authority
 31	memberAuth := auth.Authority().(*MemberAuthority)
 32	if err := memberAuth.AddMember(0, cur, address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")); err != nil {
 33		panic(err)
 34	}
 35}
 36
 37// Example_contractAuthority demonstrates a contract-based authority.
 38//
 39// A plain NewContractAuthority accepts exactly one principal:
 40// chain.PackageAddress(path). Point `path` at the principal you want to
 41// ASSERT -- normally the governance realm that will drive the action --
 42// and authorize with DoByPrevious, so the comparison is against whoever
 43// crossed in. See NewContractAuthority's godoc.
 44//
 45// Do NOT pair a plain ContractAuthority on your OWN path with
 46// DoByCurrent. rlm.Address() inside any crossing frame of a realm is
 47// unconditionally PackageAddress(ownPath), so that gate compares the
 48// realm to itself, can never reject, and any exported crossing
 49// entrypoint next to it becomes an unauthenticated privileged write --
 50// the self-comparing-gate shape. Own-path is right only when something
 51// OTHER than your own frame supplies the caller, i.e. DoByPrevious from
 52// a realm you deliberately let call in, or Transfer.
 53//
 54// Nothing here catches a wrong pairing: Example_* functions that take
 55// any parameter are never executed by `gno test` (see isExampleFunc in
 56// gnovm/pkg/test/test.go -- it rejects on method receiver, parameters or
 57// results; "// Output:" plays no part in the predicate, so adding one
 58// does NOT make the body run), so a sentinel panic in here still reports
 59// ok. filetests/z_contract_authority_shape_filetest.gno executes the
 60// gate from a real realm instead.
 61//
 62// Corollary of the identity gate: do not export anything that returns a
 63// crossing closure of this realm, or callers inherit the authority.
 64func Example_contractAuthority(cur realm) {
 65	// This realm asserts "the governance realm governs me".
 66	auth := NewWithAuthority(
 67		NewContractAuthority(
 68			"gno.land/r/gov/dao", // the principal asserted, not this realm
 69			mockDAOHandler,       // defined elsewhere for example
 70		),
 71	)
 72
 73	// Authorized only when gno.land/r/gov/dao is the realm that crossed
 74	// into this function -- in practice, when a passed proposal executes.
 75	// Every other caller presents its own address here and is refused,
 76	// which is the whole point of the gate. Never discard this error.
 77	if err := auth.DoByPrevious(0, cur, "update_params", func() error {
 78		return nil
 79	}); err != nil {
 80		panic(err)
 81	}
 82}
 83
 84// Example_restrictedContractAuthority demonstrates a contract authority with member-only proposals
 85func Example_restrictedContractAuthority(cur realm) {
 86	// Initialize member authority for proposers
 87	proposerAuth := NewMemberAuthority(
 88		address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"), // admin1
 89		address("g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj"), // admin2
 90	)
 91
 92	// Create contract authority with restricted proposers
 93	auth := NewWithAuthority(
 94		NewRestrictedContractAuthority(
 95			"gno.land/r/demo/dao",
 96			mockDAOHandler,
 97			proposerAuth,
 98		),
 99	)
100
101	// Only members can propose, and contract must approve.
102	//
103	// DoByPrevious, not DoByCurrent: the proposer set holds EOA
104	// addresses, and DoByCurrent would present this realm's own address,
105	// which is in no member set -- the proposer would reject and the
106	// action would silently never run.
107	if err := auth.DoByPrevious(0, cur, "update_params", func() error {
108		// Executes after:
109		// 1. Proposer initiates
110		// 2. DAO approves
111		return nil
112	}); err != nil {
113		panic(err)
114	}
115}
116
117// Example_switchingAuthority demonstrates switching from member to contract
118// authority.
119//
120// Note what a plain ContractAuthority on a FOREIGN path means after the
121// transfer: this realm loses the ability to take the authority back, and
122// DoByCurrent against it is dead. It is NOT a one-way door in the
123// stronger sense an earlier draft implied — the foreign realm can still
124// drive and rotate it via Previous() once it crosses in, which is the
125// intended async-DAO shape. What is given up is the original owner's
126// claim, not the authority's mutability. (The ADR for this change states
127// the same thing; keep the two in step.) To keep the authority here
128// while letting others propose, transfer to
129// NewRestrictedContractAuthority(ownPath, handler, proposerAuth)
130// instead.
131func Example_switchingAuthority(cur realm) {
132	// Start with member authority.
133	//
134	// Seed the member set with Previous(), not Address(): Transfer
135	// derives its principal as rlm.Previous().Address(), so a set
136	// containing only cur.Address() authorizes nobody but a
137	// same-package cross-call, and the Transfer below would abort for
138	// every external caller — including a realm that copies this into
139	// init(cur realm), which then fails its deploy tx. Matches
140	// Example_basic and NewWithMembers' godoc.
141	auth := NewWithMembers(cur.Previous().Address())
142
143	// Create and switch to contract authority — control moves to
144	// gno.land/r/demo/dao.
145	daoAuthority := NewContractAuthority(
146		"gno.land/r/demo/dao",
147		mockDAOHandler,
148	)
149	if err := auth.Transfer(0, cur, daoAuthority); err != nil {
150		panic(err)
151	}
152}
153
154// Mock handler for examples
155func mockDAOHandler(title string, action PrivilegedAction) error {
156	return action()
157}