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.

owner.gno

3.28 Kb · 98 lines
 1package gnosplit
 2
 3import (
 4	"chain"
 5	"strings"
 6)
 7
 8// The realm's owner, the deployer, holds one power: naming the release that
 9// takes over (SetSuccessor), once. It cannot touch a group. The role passes
10// by Transfer then Accept; Renounce drops it for good.
11var (
12	owner     address // "" once renounced
13	pending   address // the address a Transfer offered the role to
14	successor string  // the pkgpath of the next release, "" until named
15)
16
17// setUp is init's owner half. Only `gno test` (chain "dev") runs with no
18// signer, and an owner "" holds no power.
19func setUp(deployer address, chainID string) {
20	if deployer == "" && chainID != "dev" {
21		panic("gnosplit: no owner: deploy gnosplit from an account")
22	}
23	owner = deployer
24}
25
26// Owner is the realm's owner, "" once renounced.
27func Owner() address { return owner }
28
29// Successor is the pkgpath of the release that takes groups over, "" if none.
30func Successor() string { return successor }
31
32func isOwner(a address) bool { return owner != "" && a == owner }
33
34// Transfer offers the role to another address, which takes it with Accept.
35func Transfer(cur realm, to address) {
36	if !isOwner(cur.Previous().Address()) {
37		panic("gnosplit: only the owner can transfer the role")
38	}
39	if !to.IsValid() {
40		panic("gnosplit: not an address: " + to.String())
41	}
42	pending = to
43	chain.Emit(EventOwnerOffered, "to", to.String())
44}
45
46// Accept takes the role a Transfer offered the caller.
47func Accept(cur realm) {
48	caller := cur.Previous().Address()
49	if owner == "" || pending == "" || caller != pending {
50		panic("gnosplit: no transfer of the role is offered to you")
51	}
52	owner, pending = caller, ""
53	chain.Emit(EventOwnerChanged, "owner", owner.String())
54}
55
56// Renounce gives the role up for good.
57func Renounce(cur realm) {
58	if !isOwner(cur.Previous().Address()) {
59		panic("gnosplit: only the owner can renounce the role")
60	}
61	owner, pending = "", ""
62	chain.Emit(EventOwnerChanged, "owner", "")
63}
64
65// SetSuccessor names the release that takes groups over, once: a realm under
66// this one's namespace, like gno.land/r/<ns>/gnosplit/v2. From then on that
67// realm can move a group with MoveOut; nothing moves by itself.
68func SetSuccessor(cur realm, pkgpath string) {
69	if !isOwner(cur.Previous().Address()) {
70		panic("gnosplit: only the owner can name a successor")
71	}
72	if successor != "" {
73		panic("gnosplit: the successor is already " + successor)
74	}
75	ns := self[:strings.LastIndex(self, "/")+1] // "gno.land/r/<ns>/gnosplit/"
76	if !strings.HasPrefix(pkgpath, ns) || pkgpath == self || len(pkgpath) > 100 || strings.ContainsAny(pkgpath, " :?#") {
77		panic("gnosplit: a successor is a sibling release under " + ns)
78	}
79	successor = pkgpath
80	chain.Emit(EventSuccessorSet, "pkgpath", pkgpath)
81}
82
83// MoveOut marks a group as taken over and returns it, as Export writes it.
84// Only the successor realm can call it, which decides when a group moves
85// (when one of its editors asks). The group stays readable here, frozen.
86func MoveOut(cur realm, group string) string {
87	prev := cur.Previous()
88	if successor == "" || !prev.IsCode() || prev.PkgPath() != successor {
89		panic("gnosplit: only the successor can move a group")
90	}
91	g := mustGroup(group)
92	if g.Moved {
93		panic("gnosplit: group " + group + " already moved")
94	}
95	g.Moved = true
96	chain.Emit(EventGroupMoved, "group", itoa(g.ID), "to", successor)
97	return Export(group)
98}