Kind Realm (renderable)
Name v1
Namespace gnoswap / gov / governance
Exported functions n/a — Gnoland RPC unavailable (functions): rpc abci_query: HTTP 500
Module gno.land/r/gnoswap/gov/governance/v1
gno 0.9 parameter_registry.gno gno
⧉
1 package governance 2 3 import ( 4 "strings" 5 6 prbac "gno.land/p/gnoswap/rbac/v1" 7 ufmt "gno.land/p/nt/ufmt/v0" 8 Gnoland RPC unavailable (functions): rpc abci_query: HTTP 500
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
Render unavailable
rate limit exceeded — the render query is served by the Gnoland archive RPC.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
9 cm "gno.land/r/gnoswap/common"
10 cp "gno.land/r/gnoswap/community_pool/v1"
11 en "gno.land/r/gnoswap/emission"
12 "gno.land/r/gnoswap/rbac/v1"
13
14 "gno.land/r/gnoswap/gov/governance"
15 gs "gno.land/r/gnoswap/gov/staker"
16 lp "gno.land/r/gnoswap/launchpad"
17 pl "gno.land/r/gnoswap/pool"
18 pos "gno.land/r/gnoswap/position"
19 pf "gno.land/r/gnoswap/protocol_fee"
20 rr "gno.land/r/gnoswap/router"
21 sr "gno.land/r/gnoswap/staker"
22
23 "gno.land/r/gnoswap/halt/v1"
24 )
25
26 // globalParameterRegistry is initialized once and reused for all validation and execution.
27 // This provides consistent validation at proposal creation time and execution time.
28 var globalParameterRegistry *ParameterRegistry
29
30 func init() {
31 globalParameterRegistry = CreateParameterHandlers()
32 }
33
34 // Package paths
35 const (
36 GNS_TOKEN_KEY = "gno.land/r/gnoswap/gns.GNS"
37 HALT_PATH = "gno.land/r/gnoswap/halt/v1"
38 RBAC_PATH = "gno.land/r/gnoswap/rbac/v1"
39 ACCESS_PATH = "gno.land/r/gnoswap/access/v1"
40 EMISSION_PATH = "gno.land/r/gnoswap/emission"
41 COMMON_PATH = "gno.land/r/gnoswap/common"
42 POOL_PATH = "gno.land/r/gnoswap/pool"
43 POSITION_PATH = "gno.land/r/gnoswap/position"
44 ROUTER_PATH = "gno.land/r/gnoswap/router"
45 STAKER_PATH = "gno.land/r/gnoswap/staker"
46 LAUNCHPAD_PATH = "gno.land/r/gnoswap/launchpad"
47 PROTOCOL_FEE_PATH = "gno.land/r/gnoswap/protocol_fee"
48 COMMUNITY_POOL_PATH = "gno.land/r/gnoswap/community_pool/v1"
49 GOV_GOVERNANCE_PATH = "gno.land/r/gnoswap/gov/governance"
50 GOV_STAKER_PATH = "gno.land/r/gnoswap/gov/staker"
51 )
52
53 // ParameterHandler interface defines the contract for parameter execution handlers.
54 // Each handler is responsible for executing specific parameter changes in the system.
55 type ParameterHandler interface {
56 // Execute processes the parameters and applies the changes to the system.
57 // The `_ int, rlm realm` discriminator pair forwards the governance proxy's
58 // realm value into the handler so any cross-realm calls inside the closure
59 // run under the proxy's identity (the only address with caller-allowlist
60 // permission against the targeted /r/ realms).
61 //
62 // Parameters:
63 // - _: integer discriminator required by the crossing entrypoint; callers use 0
64 // - rlm: current governance proxy realm context forwarded to the handler
65 // - params: serialized parameter values to validate and apply in handler order
66 //
67 // Returns:
68 // - error: nil when the parameter change succeeds, or an execution/validation error
69 Execute(_ int , rlm realm, params [] string ) error
70 }
71
72 // ParameterHandlerOptions contains the configuration and execution logic for a parameter handler.
73 // This struct encapsulates all information needed to identify and execute a parameter change.
74 //
75 // NOTE: handlerFunc uses `rlm realm` (rather than `cur realm`) as the realm
76 // parameter name. The v2 preprocessor reserves the `cur` name for the first
77 // realm-type parameter of top-level crossing function declarations and
78 // `t.Run` closures only; using it as the realm-parameter name on a
79 // multi-parameter struct-field function value trips a parser check
80 // ("only the first realm type argument of a crossing function may have name
81 // `cur`"). Naming it `rlm` keeps the lowering identical without the syntax
82 // constraint.
83 type ParameterHandlerOptions struct {
84 pkgPath string // Package path of the target contract
85 function string // Function name to be called
86 paramCount int // Expected number of parameters
87 handlerFunc func (_ int , rlm realm, _ [] string ) error // Function that executes the parameter change
88 paramValidators []paramValidator // Optional per-parameter validators for proposal-time checks
89 compositeValidator compositeValidator // Optional cross-parameter validator for static business rules
90 }
91
92 // paramValidator validates a single parameter value and returns an error on failure.
93 type paramValidator func ( string ) error
94
95 // compositeValidator validates relationships between a handler's parameters.
96 // It must only enforce deterministic, state-independent rules so that a
97 // proposal is not rejected merely because on-chain state changes while voting.
98 type compositeValidator func ([] string ) error
99
100 // NewParameterHandlerOptions creates a new parameter handler with the specified configuration.
101 //
102 // Parameters:
103 // - pkgPath: package path of the target contract
104 // - function: function name to be called
105 // - paramCount: expected number of parameters
106 // - handlerFunc: callback receiving the discriminator, propagated realm, and serialized parameters to execute the change
107 // - paramValidators: optional validators for each parameter (must match paramCount if provided)
108 //
109 // Returns:
110 // - ParameterHandler: configured parameter handler interface
111 func NewParameterHandlerOptions(
112 pkgPath,
113 function string ,
114 paramCount int ,
115 handlerFunc func (_ int , rlm realm, _ [] string ) error ,
116 paramValidators ...paramValidator,
117 ) ParameterHandler {
118 if len(paramValidators) > 0 && len(paramValidators) != paramCount {
119 panic(ufmt.Sprintf(
120 "invalid validator count for %s:%s: expected %d, got %d" ,
121 pkgPath, function, paramCount, len(paramValidators),
122 ))
123 }
124
125 return &ParameterHandlerOptions{
126 pkgPath: pkgPath,
127 function: function,
128 paramCount: paramCount,
129 handlerFunc: handlerFunc,
130 paramValidators: paramValidators,
131 }
132 }
133
134 // HandlerKey generates a unique key for this handler based on package path and function name.
135 //
136 // Returns:
137 // - string: unique identifier for the handler
138 func (h *ParameterHandlerOptions) HandlerKey() string {
139 return makeHandlerKey(h.pkgPath, h.function)
140 }
141
142 // Execute validates parameter count and executes the handler function.
143 // This method ensures the correct number of parameters are provided before execution.
144 //
145 // Parameters:
146 // - _: integer discriminator required by the crossing entrypoint; callers use 0
147 // - rlm: governance proxy realm threaded into the wrapped handler
148 // - params: serialized parameter values to pass to the handler
149 //
150 // Returns:
151 // - error: parameter-count error or the error returned by the wrapped handler
152 func (h *ParameterHandlerOptions) Execute(_ int , rlm realm, params [] string ) error {
153 if len(params) != h.paramCount {
154 return ufmt.Errorf( "expected %d parameters, got %d" , h.paramCount, len(params))
155 }
156
157 return h.handlerFunc( 0 , rlm, params)
158 }
159
160 // ValidateParams checks the parameter count and runs configured individual and composite validators without executing the handler.
161 //
162 // Parameters:
163 // - params: serialized parameter values to validate in handler order
164 //
165 // Returns:
166 // - error: nil when all configured checks pass, or the first count/type/business-rule validation error
167 func (h *ParameterHandlerOptions) ValidateParams(params [] string ) error {
168 if len(params) != h.paramCount {
169 return ufmt.Errorf(
170 "expected %d parameters for %s, got %d" ,
171 h.paramCount, h.HandlerKey(), len(params),
172 )
173 }
174
175 if len(h.paramValidators) > 0 {
176 if len(h.paramValidators) != h.paramCount {
177 return ufmt.Errorf(
178 "validator count mismatch for %s: expected %d validator(s), got %d" ,
179 h.HandlerKey(), h.paramCount, len(h.paramValidators),
180 )
181 }
182
183 for i, validator := range h.paramValidators {
184 if validator == nil {
185 continue
186 }
187
188 if err := validator(params[i]); err != nil {
189 return ufmt.Errorf( "param[%d]: %v" , i, err)
190 }
191 }
192 }
193
194 if h.compositeValidator != nil {
195 if err := h.compositeValidator(params); err != nil {
196 return err
197 }
198 }
199
200 return nil
201 }
202
203 // ParameterRegistry manages the collection of parameter handlers for governance execution.
204 // This registry allows proposals to execute parameter changes across different system contracts.
205 type ParameterRegistry struct {
206 handlers map [ string ]ParameterHandlerOptions // Map storing handler configurations keyed by package:function
207 }
208
209 // Register adds a new parameter handler to the registry.
210 // Each handler is identified by a unique combination of package path and function name.
211 //
212 // Parameters:
213 // - handler: parameter handler configuration to register
214 func (r *ParameterRegistry) Register(handler ParameterHandlerOptions) {
215 r.handlers[handler.HandlerKey()] = handler
216 }
217
218 // Handler retrieves a parameter handler by its package:function key.
219 // This method is used during proposal execution to find the appropriate handler.
220 //
221 // Parameters:
222 // - key: handler key returned by HandlerKey, in "pkgPath:function" format
223 //
224 // Returns:
225 // - ParameterHandler: the matching parameter handler
226 // - error: error if the key has no registered handler
227 func (r *ParameterRegistry) Handler(key string ) (ParameterHandler, error ) {
228 // Retrieve handler from registry
229 handler, exists := r.handlers[key]
230 if !exists {
231 return nil , ufmt.Errorf( "handler not found for %s" , key)
232 }
233
234 return &handler, nil
235 }
236
237 // NewParameterRegistry creates a new empty parameter registry.
238 //
239 // Returns:
240 // - *ParameterRegistry: new registry instance
241 func NewParameterRegistry() *ParameterRegistry {
242 return &ParameterRegistry{handlers: make( map [ string ]ParameterHandlerOptions)}
243 }
244
245 // makeHandlerKey creates a unique identifier for a handler based on package path and function.
246 //
247 // Parameters:
248 // - pkgPath: package path of the target contract
249 // - function: function name to be called
250 //
251 // Returns:
252 // - string: unique key in format "pkgPath:function"
253 func makeHandlerKey(pkgPath, function string ) string {
254 return pkgPath + ":" + function
255 }
256
257 // CreateParameterHandlers initializes and configures all supported parameter handlers.
258 // This function defines all the parameter changes that can be executed through governance proposals.
259 // It covers configuration changes for various system components including pools, staking, fees, etc.
260 //
261 // Returns:
262 // - *ParameterRegistry: fully configured registry with all supported handlers
263 func CreateParameterHandlers() *ParameterRegistry {
264 registry := NewParameterRegistry()
265
266 // Define all handler configurations for different system components.
267 //
268 // Each closure receives `(_ int, rlm realm, params []string)` and threads
269 // `rlm` into the targeted /r/ realm call. The closure is invoked from
270 // ParameterHandlerOptions.Execute which forwards the governance proxy's
271 // realm value, so cross-realm calls land on the targeted realm with the
272 // governance proxy as the immediate caller.
273 handlers := []*ParameterHandlerOptions{
274 // Community pool token transfers
275 {
276 pkgPath: COMMUNITY_POOL_PATH,
277 function: "TransferToken" ,
278 paramCount: 3 ,
279 paramValidators: []paramValidator{
280 stringValidator, // pkgPath
281 addressValidator, // to
282 positiveInt64Validator( "amount" ),
283 },
284 handlerFunc: func (_ int , rlm realm, params [] string ) error {
285 // Transfer tokens from community pool to specified address
286 cp.TransferToken(
287 cross(rlm),
288 params[ 0 ], // pkgPath
289 address(params[ 1 ]), // to
290 parseNumber(params[ 2 ], kindInt64).( int64 ), // amount
291 )
292
293 return nil
294 },
295 },
296 // Emission distribution configuration
297 {
298 pkgPath: EMISSION_PATH,
299 function: "SetDistributionStartTime" ,
300 paramCount: 1 ,
301 paramValidators: []paramValidator{
302 numberValidator(kindInt64), // start time
303 },
304 handlerFunc: func (_ int , rlm realm, params [] string ) error {
305 // Set distribution start time
306 en.SetDistributionStartTime(cross(rlm), parseInt64(params[ 0 ]))
307
308 return nil
309 },
310 },
311 {
312 pkgPath: EMISSION_PATH,
313 function: "ChangeDistributionPct" ,
314 paramCount: 4 ,
315 paramValidators: []paramValidator{
316 numberValidator(kindInt64), // liquidityStakerPct
317 numberValidator(kindInt64), // devOpsPct
318 numberValidator(kindInt64), // communityPoolPct
319 numberValidator(kindInt64), // govStakerPct
320 },
321 compositeValidator: distributionPctCompositeValidator,
322 handlerFunc: func (_ int , rlm realm, params [] string ) error {
323 liquidityStakerPct := parseNumber(params[ 0 ], kindInt64).( int64 )
324 devOpsPct := parseNumber(params[ 1 ], kindInt64).( int64 )
325 communityPoolPct := parseNumber(params[ 2 ], kindInt64).( int64 )
326 govStakerPct := parseNumber(params[ 3 ], kindInt64).( int64 )
327
328 en.ChangeDistributionPct(
329 cross(rlm),
330 liquidityStakerPct,
331 devOpsPct,
332 communityPoolPct,
333 govStakerPct,
334 )
335
336 return nil
337 },
338 },
339 // Governance configuration changes
340 {
341 pkgPath: GOV_GOVERNANCE_PATH,
342 function: "Reconfigure" ,
343 paramCount: 7 ,
344 paramValidators: []paramValidator{
345 numberValidator(kindInt64), // votingStartDelay
346 numberValidator(kindInt64), // votingPeriod
347 numberValidator(kindInt64), // votingWeightSmoothingDuration
348 numberValidator(kindInt64), // quorum
349 numberValidator(kindInt64), // proposalCreationThreshold
350 numberValidator(kindInt64), // executionDelay
351 numberValidator(kindInt64), // executionWindow
352 },
353 handlerFunc: func (_ int , rlm realm, params [] string ) error {
354 // Parse governance configuration parameters
355 votingStartDelay := parseInt64(params[ 0 ])
356 votingPeriod := parseInt64(params[ 1 ])
357 votingWeightSmoothingDuration := parseInt64(params[ 2 ])
358 quorum := parseInt64(params[ 3 ])
359 proposalCreationThreshold := parseInt64(params[ 4 ])
360 executionDelay := parseInt64(params[ 5 ])
361 executionWindow := parseInt64(params[ 6 ])
362
363 // Reconfigure governance parameters through governance process
364 governance.Reconfigure(
365 cross(rlm),
366 votingStartDelay,
367 votingPeriod,
368 votingWeightSmoothingDuration,
369 quorum,
370 proposalCreationThreshold,
371 executionDelay,
372 executionWindow,
373 )
374
375 return nil
376 },
377 },
378
379 // Pool protocol fee configuration
380 {
381 pkgPath: POOL_PATH,
382 function: "CollectProtocol" ,
383 paramCount: 6 ,
384 paramValidators: []paramValidator{
385 stringValidator, // token0Path
386 stringValidator, // token1Path
387 uint64Validator, // fee
388 addressValidator, // recipient
389 nonNegativeInt64Validator( "amount0Requested" ),
390 nonNegativeInt64Validator( "amount1Requested" ),
391 },
392 handlerFunc: func (_ int , rlm realm, params [] string ) error {
393 pl.CollectProtocol(
394 cross(rlm),
395 params[ 0 ], // token0Path
396 params[ 1 ], // token1Path
397 uint32 (parseUint64(params[ 2 ])), // fee
398 address(params[ 3 ]), // recipient
399 params[ 4 ], // amount0Requested
400 params[ 5 ], // amount1Requested
401 )
402
403 return nil
404 },
405 },
406 {
407 pkgPath: POOL_PATH,
408 function: "SetFeeProtocol" ,
409 paramCount: 2 ,
410 paramValidators: []paramValidator{
411 uint8RangeValidator( "feeProtocol0" ),
412 uint8RangeValidator( "feeProtocol1" ),
413 },
414 handlerFunc: func (_ int , rlm realm, params [] string ) error {
415 // Parse and validate fee protocol values
416 feeProtocol0 := parseInt64(params[ 0 ])
417 feeProtocol1 := parseInt64(params[ 1 ])
418
419 // Validate fee protocol values are within uint8 range
420 if feeProtocol0 > 255 {
421 panic(ufmt.Sprintf( "feeProtocol0 out of range: %d" , feeProtocol0))
422 }
423
424 if feeProtocol1 > 255 {
425 panic(ufmt.Sprintf( "feeProtocol1 out of range: %d" , feeProtocol1))
426 }
427
428 // Set protocol fee percentages
429 pl.SetFeeProtocol(
430 cross(rlm),
431 uint8 (feeProtocol0), // feeProtocol0
432 uint8 (feeProtocol1), // feeProtocol1
433 )
434
435 return nil
436 },
437 },
438 // Pool creation fee
439 {
440 pkgPath: POOL_PATH,
441 function: "SetPoolCreationFee" ,
442 paramCount: 1 ,
443 paramValidators: []paramValidator{
444 nonNegativeInt64Validator( "fee" ),
445 },
446 handlerFunc: func (_ int , rlm realm, params [] string ) error {
447 // Set fee required to create new pools
448 pl.SetPoolCreationFee(cross(rlm), parseInt64(params[ 0 ])) // fee
449 return nil
450 },
451 },
452 // Pool withdrawal fee
453 {
454 pkgPath: POOL_PATH,
455 function: "SetWithdrawalFee" ,
456 paramCount: 1 ,
457 paramValidators: []paramValidator{
458 uint64RangeValidator( "fee" , 1000 ),
459 },
460 handlerFunc: func (_ int , rlm realm, params [] string ) error {
461 // Set fee for withdrawing from pools
462 pl.SetWithdrawalFee(cross(rlm), parseUint64(params[ 0 ])) // fee
463 return nil
464 },
465 },
466
467 // Protocol fee distribution
468 {
469 pkgPath: PROTOCOL_FEE_PATH,
470 function: "SetDevOpsPct" ,
471 paramCount: 1 ,
472 paramValidators: []paramValidator{
473 int64RangeValidator( "pct" , 0 , 10000 ),
474 },
475 handlerFunc: func (_ int , rlm realm, params [] string ) error {
476 // Set percentage of protocol fees going to development operations
477 pf.SetDevOpsPct(cross(rlm), parseInt64(params[ 0 ])) // pct
478 return nil
479 },
480 },
481
482 // Router swap fee
483 {
484 pkgPath: ROUTER_PATH,
485 function: "SetSwapFee" ,
486 paramCount: 1 ,
487 paramValidators: []paramValidator{
488 uint64RangeValidator( "fee" , 1000 ),
489 },
490 handlerFunc: func (_ int , rlm realm, params [] string ) error {
491 // Set fee charged for token swaps
492 rr.SetSwapFee(cross(rlm), parseUint64(params[ 0 ])) // fee
493 return nil
494 },
495 },
496
497 // Staker configuration handlers
498 {
499 pkgPath: STAKER_PATH,
500 function: "SetDepositGnsAmount" ,
501 paramCount: 1 ,
502 paramValidators: []paramValidator{
503 nonNegativeInt64Validator( "amount" ),
504 },
505 handlerFunc: func (_ int , rlm realm, params [] string ) error {
506 // Set minimum GNS amount required for staking deposits
507 sr.SetDepositGnsAmount(cross(rlm), parseInt64(params[ 0 ])) // amount
508 return nil
509 },
510 },
511 {
512 pkgPath: STAKER_PATH,
513 function: "SetMinimumRewardAmount" ,
514 paramCount: 1 ,
515 paramValidators: []paramValidator{
516 nonNegativeInt64Validator( "amount" ),
517 },
518 handlerFunc: func (_ int , rlm realm, params [] string ) error {
519 // Set minimum GNS amount required for staking deposits
520 sr.SetMinimumRewardAmount(cross(rlm), parseInt64(params[ 0 ])) // amount
521 return nil
522 },
523 },
524 {
525 pkgPath: STAKER_PATH,
526 function: "SetTokenMinimumRewardAmount" ,
527 paramCount: 1 ,
528 paramValidators: []paramValidator{
529 tokenMinimumRewardAmountValidator,
530 },
531 handlerFunc: func (_ int , rlm realm, params [] string ) error {
532 // Set minimum GNS amount required for staking deposits
533 // params[0] is a string in the format "tokenPath:amount"
534 sr.SetTokenMinimumRewardAmount(cross(rlm), params[ 0 ]) // amount
535 return nil
536 },
537 },
538 {
539 pkgPath: STAKER_PATH,
540 function: "SetPoolTier" ,
541 paramCount: 2 ,
542 paramValidators: []paramValidator{
543 stringValidator, // pool
544 uint64RangeValidator( "tier" , sr.AllTierCount- 1 ),
545 },
546 handlerFunc: func (_ int , rlm realm, params [] string ) error {
547 // Assign tier level to a specific pool
548 sr.SetPoolTier(
549 cross(rlm),
550 params[ 0 ], // pool
551 parseUint64(params[ 1 ]), // tier
552 )
553 return nil
554 },
555 },
556 {
557 pkgPath: STAKER_PATH,
558 function: "ChangePoolTier" ,
559 paramCount: 2 ,
560 paramValidators: []paramValidator{
561 stringValidator, // pool
562 uint64RangeValidator( "tier" , sr.AllTierCount- 1 ),
563 },
564 handlerFunc: func (_ int , rlm realm, params [] string ) error {
565 // Change existing pool's tier level
566 sr.ChangePoolTier(
567 cross(rlm),
568 params[ 0 ], // pool
569 parseUint64(params[ 1 ]), // tier
570 )
571 return nil
572 },
573 },
574 {
575 pkgPath: STAKER_PATH,
576 function: "RemovePoolTier" ,
577 paramCount: 1 ,
578 paramValidators: []paramValidator{
579 stringValidator, // pool
580 },
581 handlerFunc: func (_ int , rlm realm, params [] string ) error {
582 // Remove tier assignment from a pool
583 sr.RemovePoolTier(cross(rlm), params[ 0 ]) // pool
584 return nil
585 },
586 },
587 {
588 pkgPath: STAKER_PATH,
589 function: "SetUnStakingFee" ,
590 paramCount: 1 ,
591 paramValidators: []paramValidator{
592 uint64RangeValidator( "fee" , 1000 ),
593 },
594 handlerFunc: func (_ int , rlm realm, params [] string ) error {
595 // Set fee charged for unstaking operations
596 fee := parseUint64(params[ 0 ])
597 sr.SetUnStakingFee(cross(rlm), fee)
598 return nil
599 },
600 },
601 {
602 pkgPath: STAKER_PATH,
603 function: "SetWarmUp" ,
604 paramCount: 2 ,
605 paramValidators: []paramValidator{
606 numberValidator(kindInt64), // percent
607 numberValidator(kindInt64), // block
608 },
609 handlerFunc: func (_ int , rlm realm, params [] string ) error {
610 // Set warm-up period configuration for staking
611 percent := parseInt64(params[ 0 ])
612 block := parseNumber(params[ 1 ], kindInt64).( int64 )
613 sr.SetWarmUp(cross(rlm), percent, block)
614
615 return nil
616 },
617 },
618
619 // System halt controls
620 {
621 pkgPath: HALT_PATH,
622 function: "SetHaltLevel" ,
623 paramCount: 1 ,
624 paramValidators: []paramValidator{
625 haltLevelValidator,
626 },
627 handlerFunc: func (_ int , rlm realm, params [] string ) error {
628 // Set system-wide halt status
629 halt.SetHaltLevel(cross(rlm), halt.HaltLevel(params[ 0 ])) // true = halt, false = no halt
630
631 return nil
632 },
633 },
634 {
635 pkgPath: HALT_PATH,
636 function: "SetOperationStatus" ,
637 paramCount: 2 ,
638 paramValidators: []paramValidator{
639 haltOperationTypeValidator,
640 boolValidator, // allowed
641 },
642 handlerFunc: func (_ int , rlm realm, params [] string ) error {
643 // Enable or disable specific operation types
644 opType := halt.OpType(params[ 0 ])
645 allowed := parseBool(params[ 1 ])
646
647 halt.SetOperationStatus(cross(rlm), opType, allowed)
648
649 return nil
650 },
651 },
652
653 // RBAC configuration
654 {
655 pkgPath: RBAC_PATH,
656 function: "RegisterRole" ,
657 paramCount: 2 ,
658 paramValidators: []paramValidator{
659 roleNameValidator,
660 addressValidator, // roleAddress
661 },
662 handlerFunc: func (_ int , rlm realm, params [] string ) error {
663 roleName := params[ 0 ]
664 roleAddress := address(params[ 1 ])
665
666 // Register a new role
667 rbac.RegisterRole(cross(rlm), roleName, roleAddress)
668
669 return nil
670 },
671 },
672 {
673 pkgPath: RBAC_PATH,
674 function: "UpdateRoleAddress" ,
675 paramCount: 2 ,
676 paramValidators: []paramValidator{
677 updatableRoleNameValidator,
678 addressValidator, // roleAddress
679 },
680 handlerFunc: func (_ int , rlm realm, params [] string ) error {
681 roleName := params[ 0 ]
682 roleAddress := address(params[ 1 ])
683
684 // Update role address
685 rbac.UpdateRoleAddress(cross(rlm), roleName, roleAddress)
686
687 return nil
688 },
689 },
690 {
691 pkgPath: RBAC_PATH,
692 function: "RemoveRole" ,
693 paramCount: 1 ,
694 paramValidators: []paramValidator{
695 removableRoleNameValidator,
696 },
697 handlerFunc: func (_ int , rlm realm, params [] string ) error {
698 roleName := params[ 0 ]
699
700 // Remove role
701 rbac.RemoveRole(cross(rlm), roleName)
702
703 return nil
704 },
705 },
706
707 // Protocol fee - SetGovStakerPct
708 {
709 pkgPath: PROTOCOL_FEE_PATH,
710 function: "SetGovStakerPct" ,
711 paramCount: 1 ,
712 paramValidators: []paramValidator{
713 int64RangeValidator( "pct" , 0 , 10000 ),
714 },
715 handlerFunc: func (_ int , rlm realm, params [] string ) error {
716 // Set percentage of protocol fees going to governance stakers
717 pf.SetGovStakerPct(cross(rlm), parseInt64(params[ 0 ])) // pct
718 return nil
719 },
720 },
721
722 // Staker - Token list management
723 {
724 pkgPath: STAKER_PATH,
725 function: "AddToken" ,
726 paramCount: 1 ,
727 paramValidators: []paramValidator{
728 stringValidator, // tokenPath
729 },
730 handlerFunc: func (_ int , rlm realm, params [] string ) error {
731 // Add token to allowed token list for external incentives
732 sr.AddToken(cross(rlm), params[ 0 ]) // tokenPath
733 return nil
734 },
735 },
736 {
737 pkgPath: STAKER_PATH,
738 function: "RemoveToken" ,
739 paramCount: 1 ,
740 paramValidators: []paramValidator{
741 stringValidator, // tokenPath
742 },
743 handlerFunc: func (_ int , rlm realm, params [] string ) error {
744 // Remove token from allowed token list
745 sr.RemoveToken(cross(rlm), params[ 0 ]) // tokenPath
746 return nil
747 },
748 },
749 {
750 pkgPath: STAKER_PATH,
751 function: "SetDeniedRewardToken" ,
752 paramCount: 2 ,
753 paramValidators: []paramValidator{
754 stringValidator, // tokenPath
755 boolValidator, // denied
756 },
757 handlerFunc: func (_ int , rlm realm, params [] string ) error {
758 // Deny or re-allow a token as an external incentive reward token
759 sr.SetDeniedRewardToken(cross(rlm), params[ 0 ], parseBool(params[ 1 ]))
760 return nil
761 },
762 },
763
764 // Staker - External incentive recovery
765 {
766 pkgPath: STAKER_PATH,
767 function: "CancelExternalIncentive" ,
768 paramCount: 2 ,
769 paramValidators: []paramValidator{
770 stringValidator, // targetPoolPath
771 stringValidator, // incentiveId
772 },
773 handlerFunc: func (_ int , rlm realm, params [] string ) error {
774 // Cancel a not-yet-started external incentive; the reward tokens
775 // and the GNS deposit are refunded to the incentive creator
776 sr.CancelExternalIncentive(
777 cross(rlm),
778 params[ 0 ], // targetPoolPath
779 params[ 1 ], // incentiveId
780 )
781 return nil
782 },
783 },
784
785 // Launchpad - Project management
786 {
787 pkgPath: LAUNCHPAD_PATH,
788 function: "CreateProject" ,
789 paramCount: 10 ,
790 paramValidators: []paramValidator{
791 stringValidator, // name
792 stringValidator, // tokenPath
793 addressValidator, // recipient
794 numberValidator(kindInt64), // depositAmount
795 stringValidator, // conditionTokens
796 stringValidator, // conditionAmounts
797 numberValidator(kindInt64), // tier30Ratio
798 numberValidator(kindInt64), // tier90Ratio
799 numberValidator(kindInt64), // tier180Ratio
800 numberValidator(kindInt64), // startTime
801 },
802 handlerFunc: func (_ int , rlm realm, params [] string ) error {
803 // Create a new launchpad project
804 lp.CreateProject(
805 cross(rlm),
806 params[ 0 ], // name
807 params[ 1 ], // tokenPath
808 address(params[ 2 ]), // recipient
809 parseNumber(params[ 3 ], kindInt64).( int64 ), // depositAmount
810 params[ 4 ], // conditionTokens
811 params[ 5 ], // conditionAmounts
812 parseNumber(params[ 6 ], kindInt64).( int64 ), // tier30Ratio
813 parseNumber(params[ 7 ], kindInt64).( int64 ), // tier90Ratio
814 parseNumber(params[ 8 ], kindInt64).( int64 ), // tier180Ratio
815 parseNumber(params[ 9 ], kindInt64).( int64 ), // startTime
816 )
817 return nil
818 },
819 },
820 // Upgrade handlers for various domains
821 {
822 pkgPath: POOL_PATH,
823 function: "UpgradeImpl" ,
824 paramCount: 1 ,
825 paramValidators: []paramValidator{
826 stringValidator, // packagePath
827 },
828 handlerFunc: func (_ int , rlm realm, params [] string ) error {
829 // Upgrade pool implementation
830 pl.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
831 return nil
832 },
833 },
834 {
835 pkgPath: POSITION_PATH,
836 function: "UpgradeImpl" ,
837 paramCount: 1 ,
838 paramValidators: []paramValidator{
839 stringValidator, // packagePath
840 },
841 handlerFunc: func (_ int , rlm realm, params [] string ) error {
842 // Upgrade position implementation
843 pos.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
844 return nil
845 },
846 },
847 {
848 pkgPath: STAKER_PATH,
849 function: "UpgradeImpl" ,
850 paramCount: 1 ,
851 paramValidators: []paramValidator{
852 stringValidator, // packagePath
853 },
854 handlerFunc: func (_ int , rlm realm, params [] string ) error {
855 // Upgrade staker implementation
856 sr.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
857 return nil
858 },
859 },
860 {
861 pkgPath: LAUNCHPAD_PATH,
862 function: "UpgradeImpl" ,
863 paramCount: 1 ,
864 paramValidators: []paramValidator{
865 stringValidator, // packagePath
866 },
867 handlerFunc: func (_ int , rlm realm, params [] string ) error {
868 // Upgrade launchpad implementation
869 lp.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
870 return nil
871 },
872 },
873 {
874 pkgPath: GOV_GOVERNANCE_PATH,
875 function: "UpgradeImpl" ,
876 paramCount: 1 ,
877 paramValidators: []paramValidator{
878 stringValidator, // targetPackagePath
879 },
880 handlerFunc: func (_ int , rlm realm, params [] string ) error {
881 // Upgrade governance implementation
882 governance.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
883 return nil
884 },
885 },
886 {
887 pkgPath: GOV_STAKER_PATH,
888 function: "UpgradeImpl" ,
889 paramCount: 1 ,
890 paramValidators: []paramValidator{
891 stringValidator, // packagePath
892 },
893 handlerFunc: func (_ int , rlm realm, params [] string ) error {
894 // Upgrade gov staker implementation
895 gs.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
896 return nil
897 },
898 },
899 {
900 pkgPath: ROUTER_PATH,
901 function: "UpgradeImpl" ,
902 paramCount: 1 ,
903 paramValidators: []paramValidator{
904 stringValidator, // packagePath
905 },
906 handlerFunc: func (_ int , rlm realm, params [] string ) error {
907 // Upgrade router implementation
908 rr.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
909 return nil
910 },
911 },
912 {
913 pkgPath: PROTOCOL_FEE_PATH,
914 function: "UpgradeImpl" ,
915 paramCount: 1 ,
916 paramValidators: []paramValidator{
917 stringValidator, // packagePath
918 },
919 handlerFunc: func (_ int , rlm realm, params [] string ) error {
920 // Upgrade protocol fee implementation
921 pf.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
922 return nil
923 },
924 },
925 {
926 pkgPath: COMMON_PATH,
927 function: "UpgradeImpl" ,
928 paramCount: 1 ,
929 paramValidators: []paramValidator{
930 stringValidator, // packagePath
931 },
932 handlerFunc: func (_ int , rlm realm, params [] string ) error {
933 // Upgrade common (token resolution) implementation
934 cm.UpgradeImpl(cross(rlm), params[ 0 ]) // packagePath
935 return nil
936 },
937 },
938 }
939
940 // Register all configured handlers in the registry
941 registerHandlers(registry, handlers)
942
943 return registry
944 }
945
946 // registerHandlers batch registers all configured handlers into the registry.
947 // This helper function processes the handler configuration array and adds each handler to the registry.
948 //
949 // Parameters:
950 // - registry: the parameter registry to add handlers to
951 // - handlerOptions: slice of handler configurations to register
952 func registerHandlers(registry *ParameterRegistry, handlerOptions []*ParameterHandlerOptions) {
953 for _, handlerOption := range handlerOptions {
954 registry.Register(*handlerOption)
955 }
956 }
957
958 // runValidator executes a validator function and converts panics to errors.
959 func runValidator(fn func ()) (err error ) {
960 defer func () {
961 if r := recover(); r != nil {
962 if e, ok := r.( error ); ok {
963 err = e
964 return
965 }
966 err = ufmt.Errorf( "%v" , r)
967 }
968 }()
969
970 fn()
971 return nil
972 }
973
974 // Basic reusable validators for proposal-time type checking.
975 var (
976 stringValidator = func (s string ) error {
977 return nil
978 }
979 boolValidator = func (s string ) error {
980 return runValidator( func () {
981 parseBool(s)
982 })
983 }
984 uint64Validator = func (s string ) error {
985 return runValidator( func () {
986 parseUint64(s)
987 })
988 }
989 addressValidator = func (s string ) error {
990 return runValidator( func () {
991 addr := address(s)
992 if !addr.IsValid() {
993 panic(ufmt.Sprintf( "invalid address: %s" , addr))
994 }
995 })
996 }
997 )
998
999 func numberValidator(kind numberKind) paramValidator {
1000 return func (s string ) error {
1001 return runValidator( func () {
1002 parseNumber(s, kind)
1003 })
1004 }
1005 }
1006
1007 func uint8RangeValidator(name string ) paramValidator {
1008 return func (s string ) error {
1009 return runValidator( func () {
1010 value := parseInt64(s)
1011 if value < 0 || value > 255 {
1012 panic(ufmt.Sprintf( "%s out of range: %d" , name, value))
1013 }
1014 })
1015 }
1016 }
1017
1018 func roleNameValidator(s string ) error {
1019 return runValidator( func () {
1020 roleName := strings.TrimSpace(s)
1021 if roleName == "" {
1022 panic(ufmt.Sprintf( "role name is empty: %q" , s))
1023 }
1024 })
1025 }
1026
1027 func updatableRoleNameValidator(s string ) error {
1028 return runValidator( func () {
1029 roleName := strings.TrimSpace(s)
1030 if err := roleNameValidator(roleName); err != nil {
1031 panic(err)
1032 }
1033
1034 if roleName == prbac.ROLE_ADMIN.String() {
1035 panic(ufmt.Sprintf( "admin role cannot be updated: %s" , roleName))
1036 }
1037 })
1038 }
1039
1040 func removableRoleNameValidator(s string ) error {
1041 return runValidator( func () {
1042 roleName := strings.TrimSpace(s)
1043 if err := roleNameValidator(roleName); err != nil {
1044 panic(err)
1045 }
1046
1047 if prbac.IsSystemRole(roleName) {
1048 panic(ufmt.Sprintf( "system role cannot be removed: %s" , roleName))
1049 }
1050 })
1051 }
1052
1053 func nonNegativeInt64Validator(name string ) paramValidator {
1054 return func (s string ) error {
1055 return runValidator( func () {
1056 value := parseInt64(s)
1057 if value < 0 {
1058 panic(ufmt.Sprintf( "%s must be non-negative: %d" , name, value))
1059 }
1060 })
1061 }
1062 }
1063
1064 func positiveInt64Validator(name string ) paramValidator {
1065 return func (s string ) error {
1066 return runValidator( func () {
1067 value := parseInt64(s)
1068 if value <= 0 {
1069 panic(ufmt.Sprintf( "%s must be positive: %d" , name, value))
1070 }
1071 })
1072 }
1073 }
1074
1075 func int64RangeValidator(name string , min, max int64 ) paramValidator {
1076 return func (s string ) error {
1077 return runValidator( func () {
1078 value := parseInt64(s)
1079 if value < min || value > max {
1080 panic(ufmt.Sprintf( "%s must be in range %d to %d: %d" , name, min, max, value))
1081 }
1082 })
1083 }
1084 }
1085
1086 func uint64RangeValidator(name string , max uint64 ) paramValidator {
1087 return func (s string ) error {
1088 return runValidator( func () {
1089 value := parseUint64(s)
1090 if value > max {
1091 panic(ufmt.Sprintf( "%s must be in range 0 to %d: %d" , name, max, value))
1092 }
1093 })
1094 }
1095 }
1096
1097 func haltLevelValidator(s string ) error {
1098 return runValidator( func () {
1099 if !halt.HaltLevel(s).IsValid() {
1100 panic(ufmt.Sprintf( "invalid halt level: %s" , s))
1101 }
1102 })
1103 }
1104
1105 func haltOperationTypeValidator(s string ) error {
1106 return runValidator( func () {
1107 if !halt.OpType(s).IsValid() {
1108 panic(ufmt.Sprintf( "invalid operation type: %s" , s))
1109 }
1110 })
1111 }
1112
1113 func tokenMinimumRewardAmountValidator(s string ) error {
1114 return runValidator( func () {
1115 parts := strings.SplitN(s, ":" , 2 )
1116 if len(parts) != 2 || parts[ 0 ] == "" {
1117 panic( "token minimum reward amount must be tokenPath:amount" )
1118 }
1119 amount := parseInt64(parts[ 1 ])
1120 if amount < 0 {
1121 panic(ufmt.Sprintf( "minimum reward amount must be non-negative: %d" , amount))
1122 }
1123 })
1124 }
1125
1126 func distributionPctCompositeValidator(params [] string ) error {
1127 return runValidator( func () {
1128 sum := int64 ( 0 )
1129 for i, param := range params {
1130 pct := parseInt64(param)
1131 if pct < 0 || pct > 10000 {
1132 panic(ufmt.Sprintf( "percentage %d must be in range 0 to 10000: %d" , i+ 1 , pct))
1133 }
1134 sum += pct
1135 }
1136 if sum != 10000 {
1137 panic(ufmt.Sprintf( "sum of percentages must be 10000, got %d" , sum))
1138 }
1139 })
1140 }
1141
1142 func splitExecutionsRaw(executions string ) [] string {
1143 if executions == "" {
1144 return [] string {}
1145 }
1146
1147 return strings.Split(executions, messageSeparator)
1148 }
1149
1150 func parseExecutionMessage(msg string ) (pkgPath string , function string , params [] string , partCount int ) {
1151 parts := strings.Split(msg, parameterSeparator)
1152 partCount = len(parts)
1153 if partCount != 3 {
1154 return "" , "" , nil , partCount
1155 }
1156
1157 pkgPath = parts[ 0 ]
1158 function = parts[ 1 ]
1159 if parts[ 2 ] == "" {
1160 return pkgPath, function, [] string {}, partCount
1161 }
1162
1163 return pkgPath, function, strings.Split(parts[ 2 ], "," ), partCount
1164 }
1165
1166 // validateExecutions validates that all executions in a parameter change proposal
1167 // correspond to registered handlers in the global parameter registry.
1168 // This function performs comprehensive validation including:
1169 // - Basic format validation (count, structure)
1170 // - Handler existence verification in the registry
1171 // - Parameter count validation against handler expectations
1172 //
1173 // Parameters:
1174 // - numToExecute: number of parameter changes to execute
1175 // - msgs: pre-split slice of execution messages, where each message
1176 // is formatted as <pkgPath>*EXE*<function>*EXE*<params>
1177 //
1178 // Returns:
1179 // - error: validation error if any execution is invalid
1180 func validateExecutions(numToExecute int64 , msgs [] string ) error {
1181 // Validate execution count is positive
1182 if numToExecute <= 0 {
1183 return makeErrorWithDetails(
1184 errInvalidInput,
1185 "numToExecute is less than or equal to 0" ,
1186 )
1187 }
1188
1189 // Check if executions are empty
1190 if len(msgs) == 0 {
1191 return makeErrorWithDetails(
1192 errInvalidInput,
1193 "executions is empty" ,
1194 )
1195 }
1196
1197 // Validate execution count doesn't exceed maximum
1198 if numToExecute > maxNumberOfExecution {
1199 return makeErrorWithDetails(
1200 errInvalidInput,
1201 ufmt.Sprintf( "numToExecute is greater than %d" , maxNumberOfExecution),
1202 )
1203 }
1204
1205 msgCount := len(msgs)
1206 // Validate execution count matches message count
1207 if msgCount != int (numToExecute) {
1208 return makeErrorWithDetails(
1209 errInvalidInput,
1210 ufmt.Sprintf( "executions count (%d) does not match numToExecute (%d)" , len(msgs), numToExecute),
1211 )
1212 }
1213
1214 // Parse and validate each execution message
1215 for i, execution := range msgs {
1216 pkgPath, function, params, partCount := parseExecutionMessage(execution)
1217 if partCount != 3 {
1218 // Provide more helpful error message based on what's wrong
1219 detail := ufmt.Sprintf( "execution[%d]: expected 3 parts (pkgPath, function, params), got %d" , i, partCount)
1220 return makeErrorWithDetails(
1221 errInvalidMessageFormat,
1222 detail,
1223 )
1224 }
1225
1226 // Validate package path and function are not empty
1227 if pkgPath == "" {
1228 return makeErrorWithDetails(
1229 errInvalidInput,
1230 ufmt.Sprintf( "execution[%d]: package path is empty" , i),
1231 )
1232 }
1233
1234 if function == "" {
1235 return makeErrorWithDetails(
1236 errInvalidInput,
1237 ufmt.Sprintf( "execution[%d]: function name is empty" , i),
1238 )
1239 }
1240
1241 // Check if handler exists in registry
1242 key := makeHandlerKey(pkgPath, function)
1243 handler, err := globalParameterRegistry.Handler(key)
1244 if err != nil {
1245 return makeErrorWithDetails(
1246 errInvalidExecution,
1247 ufmt.Sprintf( "execution[%d]: %s (key: %s)" , i, err.Error(), key),
1248 )
1249 }
1250
1251 // Get expected parameter count from handler
1252 handlerOpts, ok := handler.(*ParameterHandlerOptions)
1253 if !ok {
1254 return makeErrorWithDetails(
1255 errInvalidExecution,
1256 ufmt.Sprintf( "execution[%d]: failed to get handler options" , i),
1257 )
1258 }
1259
1260 // Validate parameter types/format ahead of proposal creation
1261 if err := handlerOpts.ValidateParams(params); err != nil {
1262 return makeErrorWithDetails(
1263 errInvalidInput,
1264 ufmt.Sprintf( "execution[%d]: %v" , i, err),
1265 )
1266 }
1267 }
1268
1269 return nil
1270 }
1271