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

state.gno

11.03 Kb · 277 lines
  1package manager
  2
  3import "gno.land/p/nt/ufmt/v0"
  4
  5type State struct {
  6	Roles   map[RoleId]*RoleConfig
  7	Targets map[string]*TargetConfig
  8}
  9
 10func NewState() State {
 11	return State{
 12		Roles:   make(map[RoleId]*RoleConfig),
 13		Targets: make(map[string]*TargetConfig),
 14	}
 15}
 16
 17// =================================================== GETTERS ====================================================
 18
 19// CanCall reports whether caller can call target selector immediately.
 20// This Gno port returns only immediate authorization because scheduled
 21// execution and execution delay are intentionally not ported.
 22// OpenZeppelin reference:
 23// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L140-L156
 24func (state *State) CanCall(caller address, target string, selector Selector) CanCallResult {
 25	if state.IsTargetClosed(target) {
 26		return NewCanCallResult(false)
 27	}
 28
 29	role := state.GetTargetFunctionRole(target, selector)
 30
 31	membership := state.HasRole(role, caller)
 32	if !membership.IsMember {
 33		return NewCanCallResult(false)
 34	}
 35
 36	return NewCanCallResult(true)
 37}
 38
 39// IsAuthorized is a boolean convenience wrapper around CanCall.
 40// OpenZeppelin reference:
 41// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L140-L156
 42func (state *State) IsAuthorized(caller address, target string, selector Selector) bool {
 43	return state.CanCall(caller, target, selector).Immediate
 44}
 45
 46// HasRole reports whether account currently has an active role membership.
 47// This Gno port returns membership only because execution delay is not ported.
 48// OpenZeppelin reference:
 49// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L211-L220
 50func (state *State) HasRole(role RoleId, account address) HasRoleResult {
 51	if role == PublicRole {
 52		return NewHasRoleResult(true)
 53	}
 54
 55	roleConfig := state.getRole(role)
 56	if roleConfig == nil {
 57		return NewHasRoleResult(false)
 58	}
 59
 60	return NewHasRoleResult(roleConfig.hasMember(account, CurrentTimePoint()))
 61}
 62
 63// GetRoleAdmin returns the admin role for role, defaulting to AdminRole.
 64// OpenZeppelin reference:
 65// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L183-L186
 66func (state *State) GetRoleAdmin(role RoleId) RoleId {
 67	roleConfig := state.getRole(role)
 68	if roleConfig == nil {
 69		return AdminRole
 70	}
 71
 72	return roleConfig.adminRole()
 73}
 74
 75// GetRoleGrantDelay returns the grant delay configured for role.
 76// OpenZeppelin reference:
 77// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L193-L196
 78func (state *State) GetRoleGrantDelay(role RoleId) Delay {
 79	roleConfig := state.getRole(role)
 80	if roleConfig == nil {
 81		return 0
 82	}
 83
 84	return roleConfig.grantDelay()
 85}
 86
 87// GetTargetFunctionRole returns the role required for target selector.
 88// Unconfigured selectors default to AdminRole in this Gno representation.
 89// OpenZeppelin reference:
 90// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L173-L176
 91func (state *State) GetTargetFunctionRole(target string, selector Selector) RoleId {
 92	targetConfig := state.getTarget(target)
 93	if targetConfig == nil {
 94		return AdminRole
 95	}
 96
 97	return targetConfig.functionRole(selector)
 98}
 99
100// IsTargetClosed reports whether target is closed.
101// OpenZeppelin reference:
102// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L168-L171
103func (state *State) IsTargetClosed(target string) bool {
104	targetConfig := state.getTarget(target)
105
106	return targetConfig != nil && targetConfig.isClosed()
107}
108
109// =============================================== ROLE MANAGEMENT ===============================================
110
111// GrantRole grants role membership to account and returns true for a new member.
112// This Gno port retains grant delay but intentionally omits OZ execution delay.
113// OpenZeppelin references:
114// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L233-L236
115// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L271-L298
116func (state *State) GrantRole(role RoleId, account address) bool {
117	if role == PublicRole {
118		panic(errorWithDetails(errAccessManagerLockedRole, ufmt.Sprintf("role %d is locked", role)))
119	}
120
121	state.ensureRole(role)
122
123	return state.getRole(role).grant(account, CurrentTimePoint())
124}
125
126// RevokeRole revokes role membership from account and reports whether it existed.
127// OpenZeppelin references:
128// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L238-L240
129// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L300-L319
130func (state *State) RevokeRole(role RoleId, account address) bool {
131	if role == PublicRole {
132		panic(errorWithDetails(errAccessManagerLockedRole, ufmt.Sprintf("role %d is locked", role)))
133	}
134
135	state.ensureRole(role)
136
137	if role == AdminRole && state.isLastAdmin(account) {
138		panic(errAccessManagerLastAdmin)
139	}
140
141	return state.getRole(role).revoke(account)
142}
143
144// isLastAdmin reports whether account is the only currently active AdminRole
145// member. Prevents bricking the system by removing the final admin.
146func (state *State) isLastAdmin(account address) bool {
147	adminRole := state.getRole(AdminRole)
148	if adminRole == nil {
149		return false
150	}
151
152	now := CurrentTimePoint()
153	if !adminRole.hasMember(account, now) {
154		return false
155	}
156
157	for member, access := range adminRole.Members {
158		if member != account && access.isActiveAt(now) {
159			return false
160		}
161	}
162
163	return true
164}
165
166// RenounceRole revokes caller-confirmed role membership from account.
167// OpenZeppelin reference:
168// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L243-L249
169func (state *State) RenounceRole(role RoleId, account address, callerConfirmation address) bool {
170	if account != callerConfirmation {
171		panic(errAccessManagerBadConfirmation)
172	}
173
174	return state.RevokeRole(role, account)
175}
176
177// SetRoleAdmin sets the admin role that can grant or revoke role.
178// OpenZeppelin references:
179// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L251-L254
180// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L321-L337
181func (state *State) SetRoleAdmin(role RoleId, admin RoleId) {
182	RequireUnlockedConfigRole(role)
183
184	state.ensureRole(role)
185	state.getRole(role).setAdmin(admin)
186}
187
188// SetGrantDelay sets the delay before future grants of role become active.
189// OpenZeppelin references:
190// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L261-L264
191// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L357-L371
192func (state *State) SetGrantDelay(role RoleId, delay Delay) {
193	RequireUnlockedConfigRole(role)
194
195	state.ensureRole(role)
196	state.getRole(role).setGrantDelay(delay)
197}
198
199// ============================================= FUNCTION MANAGEMENT ==============================================
200
201// SetTargetFunctionRole sets the role required for target selector.
202// OpenZeppelin reference:
203// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L385-L393
204func (state *State) SetTargetFunctionRole(target string, selector Selector, role RoleId) {
205	state.ensureTarget(target)
206	state.getTarget(target).setFunctionRole(selector, role)
207}
208
209// SetTargetFunctionRoles sets the same role for multiple target selectors.
210// OpenZeppelin reference:
211// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L373-L383
212func (state *State) SetTargetFunctionRoles(target string, selectors []Selector, role RoleId) {
213	state.ensureTarget(target)
214	state.getTarget(target).setFunctionRoles(selectors, role)
215}
216
217// =============================================== MODE MANAGEMENT ================================================
218
219// SetTargetClosed sets whether target rejects calls regardless of selector role.
220// OpenZeppelin references:
221// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L412-L416
222// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L418-L426
223func (state *State) SetTargetClosed(target string, closed bool) {
224	state.ensureTarget(target)
225	state.getTarget(target).setClosed(closed)
226}
227
228// ================================================= ADMIN LOGIC ==================================================
229
230// CanAdminRole reports whether caller has the admin role required for role.
231// OpenZeppelin reference:
232// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L652-L657
233func (state *State) CanAdminRole(role RoleId, caller address) CanCallResult {
234	adminRole := state.GetRoleAdmin(role)
235
236	membership := state.HasRole(adminRole, caller)
237	if !membership.IsMember {
238		return NewCanCallResult(false)
239	}
240
241	return NewCanCallResult(true)
242}
243
244// CanManageTarget reports whether caller can manage target configuration.
245// OpenZeppelin references:
246// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L101-L105
247// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fd1781b1454fd1ef8e722282f86f9293cacf256/contracts/access/manager/AccessManager.sol#L640-L650
248func (state *State) CanManageTarget(caller address) CanCallResult {
249	membership := state.HasRole(AdminRole, caller)
250	if !membership.IsMember {
251		return NewCanCallResult(false)
252	}
253
254	return NewCanCallResult(true)
255}
256
257func (state *State) getRole(role RoleId) *RoleConfig {
258	return state.Roles[role]
259}
260
261func (state *State) getTarget(target string) *TargetConfig {
262	return state.Targets[target]
263}
264
265func (state *State) ensureRole(role RoleId) {
266	roleConfig, found := state.Roles[role]
267	if !found || roleConfig == nil {
268		state.Roles[role] = NewRoleConfig(AdminRole, 0)
269	}
270}
271
272func (state *State) ensureTarget(target string) {
273	targetConfig, found := state.Targets[target]
274	if !found || targetConfig == nil {
275		state.Targets[target] = NewTargetConfig(false)
276	}
277}