admin.gno
4.57 Kb · 167 lines
1package users
2
3import (
4 "chain"
5 "chain/runtime"
6
7 "gno.land/p/moul/addrset"
8 "gno.land/p/nt/ufmt/v0"
9
10 "gno.land/r/gov/dao"
11)
12
13const initControllerPath = "gno.land/r/sys/users/init"
14
15var controllers = addrset.Set{} // caller whitelist
16
17func init() {
18 // auto-whitelist the init controller for bootstrapping for testing chain.
19 if chainID := runtime.ChainID(); chainID == "dev" {
20 controllers.Add(chain.PackageAddress(initControllerPath))
21 }
22}
23
24// AddControllerAtGenesis allows adding a controller during chain genesis (height 0).
25// This is mostly useful for testing.
26func AddControllerAtGenesis(_ realm, addr address) {
27 height := runtime.ChainHeight()
28 if height > 0 {
29 panic("AddControllerAtGenesis can only be called at genesis (height 0)")
30 }
31
32 if !addr.IsValid() {
33 panic(ErrInvalidAddress)
34 }
35
36 controllers.Add(addr)
37}
38
39// ProposeNewController allows GovDAO to add a whitelisted caller
40func ProposeNewController(addr address) dao.ProposalRequest {
41 if !addr.IsValid() {
42 panic(ErrInvalidAddress)
43 }
44
45 cb := func(cur realm) error {
46 return addToWhitelist(addr)
47 }
48
49 desc := "This proposal adds " + addr.String() + " to `sys/users` realm's callers whitelist."
50 return dao.NewProposalRequest("Add Whitelisted Caller to \"sys/users\" Realm", desc, dao.NewSimpleExecutor(cb, ""))
51}
52
53// ProposeControllerRemoval allows GovDAO to add a whitelisted caller
54func ProposeControllerRemoval(addr address) dao.ProposalRequest {
55 if !addr.IsValid() {
56 panic(ErrInvalidAddress)
57 }
58
59 cb := func(cur realm) error {
60 return deleteFromWhitelist(addr)
61 }
62
63 desc := "This proposal removes " + addr.String() + " from `sys/users` realm's callers whitelist."
64 return dao.NewProposalRequest("Remove Whitelisted Caller From \"sys/users\" Realm", desc, dao.NewSimpleExecutor(cb, ""))
65}
66
67// ProposeControllerAdditionAndRemoval allows GovDAO to add a new caller and remove an old caller in the same proposal.
68func ProposeControllerAdditionAndRemoval(toAdd, toRemove address) dao.ProposalRequest {
69 if !toAdd.IsValid() || !toRemove.IsValid() {
70 panic(ErrInvalidAddress)
71 }
72
73 cb := func(cur realm) error {
74 err := addToWhitelist(toAdd)
75 if err != nil {
76 return err
77 }
78
79 return deleteFromWhitelist(toRemove)
80 }
81
82 desc := ufmt.Sprint(
83 "This proposal adds %s and removes %s from `sys/users` realm's callers whitelist.",
84 toAdd,
85 toRemove,
86 )
87 return dao.NewProposalRequest("Add and Remove Whitelisted Callers From \"sys/users\" Realm", desc, dao.NewSimpleExecutor(cb, ""))
88}
89
90// ProposeRegisterUser allows GovDAO to register a name without checking controllers
91func ProposeRegisterUser(name string, addr address) dao.ProposalRequest {
92 // Validate the name and address now, even though registerUser will validate again
93 if err := validateName(name); err != nil {
94 panic(err.Error())
95 }
96 if !addr.IsValid() {
97 panic(ErrInvalidAddress)
98 }
99
100 cb := func(cur realm) error {
101 return registerUser(cur, name, addr)
102 }
103
104 desc := "This proposal registers " + name + " with address " + addr.String() + " in `sys/users`."
105 return dao.NewProposalRequest("Register User to \"sys/users\" Realm", desc, dao.NewSimpleExecutor(cb, ""))
106}
107
108// ProposeUpdateName allows GovDAO to update a name with an alias without checking controllers
109func ProposeUpdateName(addr address, newName string) dao.ProposalRequest {
110 if !addr.IsValid() {
111 panic(ErrInvalidAddress)
112 }
113 if err := validateName(newName); err != nil {
114 panic(err.Error())
115 }
116
117 cb := func(cur realm) error {
118 data := ResolveAddress(addr)
119 if data == nil {
120 return ErrUserNotExistOrDeleted
121 }
122 return data.updateName(newName)
123 }
124
125 desc := "This proposal updates address " + addr.String() + " with alias " + newName + " in `sys/users`."
126 return dao.NewProposalRequest("Update Name Alias in \"sys/users\" Realm", desc, dao.NewSimpleExecutor(cb, ""))
127}
128
129// ProposeDeleteUser allows GovDAO to delete a user without checking controllers
130func ProposeDeleteUser(addr address) dao.ProposalRequest {
131 if !addr.IsValid() {
132 panic(ErrInvalidAddress)
133 }
134
135 cb := func(cur realm) error {
136 data := ResolveAddress(addr)
137 if data == nil {
138 return ErrUserNotExistOrDeleted
139 }
140 return data.delete()
141 }
142
143 desc := "This proposal deletes the user with address " + addr.String() + " in `sys/users`."
144 return dao.NewProposalRequest("Delete User in \"sys/users\" Realm", desc, dao.NewSimpleExecutor(cb, ""))
145}
146
147// Helpers
148
149func deleteFromWhitelist(addr address) error {
150 if !controllers.Has(addr) {
151 return NewErrNotWhitelisted()
152 }
153
154 if ok := controllers.Remove(addr); !ok {
155 return ErrWhitelistRemoveFailed
156 }
157
158 return nil
159}
160
161func addToWhitelist(newCaller address) error {
162 if !controllers.Add(newCaller) {
163 return ErrAlreadyWhitelisted
164 }
165
166 return nil
167}