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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

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}