parameter_registry.gno
29.93 Kb ยท 1065 lines
1package v1
2
3import (
4 "strings"
5
6 "gno.land/p/nt/avl"
7 "gno.land/p/nt/ufmt"
8
9 cp "gno.land/r/gnoswap/community_pool"
10 en "gno.land/r/gnoswap/emission"
11 "gno.land/r/gnoswap/rbac"
12
13 "gno.land/r/gnoswap/gov/governance"
14 gs "gno.land/r/gnoswap/gov/staker"
15 lp "gno.land/r/gnoswap/launchpad"
16 pl "gno.land/r/gnoswap/pool"
17 pos "gno.land/r/gnoswap/position"
18 pf "gno.land/r/gnoswap/protocol_fee"
19 rr "gno.land/r/gnoswap/router"
20 sr "gno.land/r/gnoswap/staker"
21
22 "gno.land/r/gnoswap/halt"
23)
24
25// globalParameterRegistry is initialized once and reused for all validation and execution.
26// This provides consistent validation at proposal creation time and execution time.
27var globalParameterRegistry *ParameterRegistry
28
29func init() {
30 globalParameterRegistry = CreateParameterHandlers()
31}
32
33// Package paths
34const (
35 GNS_PATH = "gno.land/r/gnoswap/gns"
36 HALT_PATH = "gno.land/r/gnoswap/halt"
37 RBAC_PATH = "gno.land/r/gnoswap/rbac"
38 ACCESS_PATH = "gno.land/r/gnoswap/access"
39 EMISSION_PATH = "gno.land/r/gnoswap/emission"
40 COMMON_PATH = "gno.land/r/gnoswap/common"
41 POOL_PATH = "gno.land/r/gnoswap/pool"
42 POSITION_PATH = "gno.land/r/gnoswap/position"
43 ROUTER_PATH = "gno.land/r/gnoswap/router"
44 STAKER_PATH = "gno.land/r/gnoswap/staker"
45 LAUNCHPAD_PATH = "gno.land/r/gnoswap/launchpad"
46 PROTOCOL_FEE_PATH = "gno.land/r/gnoswap/protocol_fee"
47 COMMUNITY_POOL_PATH = "gno.land/r/gnoswap/community_pool"
48 GOV_GOVERNANCE_PATH = "gno.land/r/gnoswap/gov/governance"
49 GOV_STAKER_PATH = "gno.land/r/gnoswap/gov/staker"
50)
51
52// ParameterHandler interface defines the contract for parameter execution handlers.
53// Each handler is responsible for executing specific parameter changes in the system.
54type ParameterHandler interface {
55 // Execute processes the parameters and applies the changes to the system
56 Execute(params []string) error
57}
58
59// ParameterHandlerOptions contains the configuration and execution logic for a parameter handler.
60// This struct encapsulates all information needed to identify and execute a parameter change.
61type ParameterHandlerOptions struct {
62 pkgPath string // Package path of the target contract
63 function string // Function name to be called
64 paramCount int // Expected number of parameters
65 handlerFunc func([]string) error // Function that executes the parameter change
66 paramValidators []paramValidator // Optional per-parameter validators for proposal-time checks
67}
68
69// paramValidator validates a single parameter value and returns an error on failure.
70type paramValidator func(string) error
71
72// NewParameterHandlerOptions creates a new parameter handler with the specified configuration.
73//
74// Parameters:
75// - pkgPath: package path of the target contract
76// - function: function name to be called
77// - paramCount: expected number of parameters
78// - handlerFunc: function that executes the parameter change
79// - paramValidators: optional validators for each parameter (must match paramCount if provided)
80//
81// Returns:
82// - ParameterHandler: configured parameter handler interface
83func NewParameterHandlerOptions(
84 pkgPath,
85 function string,
86 paramCount int,
87 handlerFunc func([]string) error,
88 paramValidators ...paramValidator,
89) ParameterHandler {
90 if len(paramValidators) > 0 && len(paramValidators) != paramCount {
91 panic(ufmt.Sprintf(
92 "invalid validator count for %s:%s: expected %d, got %d",
93 pkgPath, function, paramCount, len(paramValidators),
94 ))
95 }
96
97 return &ParameterHandlerOptions{
98 pkgPath: pkgPath,
99 function: function,
100 paramCount: paramCount,
101 handlerFunc: handlerFunc,
102 paramValidators: paramValidators,
103 }
104}
105
106// HandlerKey generates a unique key for this handler based on package path and function name.
107//
108// Returns:
109// - string: unique identifier for the handler
110func (h *ParameterHandlerOptions) HandlerKey() string {
111 return makeHandlerKey(h.pkgPath, h.function)
112}
113
114// Execute validates parameter count and executes the handler function.
115// This method ensures the correct number of parameters are provided before execution.
116//
117// Parameters:
118// - params: slice of string parameters to pass to the handler
119//
120// Returns:
121// - error: execution error if parameter count mismatch or handler execution fails
122func (h *ParameterHandlerOptions) Execute(params []string) error {
123 // Validate parameter count matches expected count
124 if len(params) != h.paramCount {
125 return ufmt.Errorf("expected %d parameters, got %d", h.paramCount, len(params))
126 }
127 return h.handlerFunc(params)
128}
129
130// ValidateParams runs parameter count and per-parameter validation without executing the handler.
131func (h *ParameterHandlerOptions) ValidateParams(params []string) error {
132 if len(params) != h.paramCount {
133 return ufmt.Errorf(
134 "expected %d parameters for %s, got %d",
135 h.paramCount, h.HandlerKey(), len(params),
136 )
137 }
138
139 if len(h.paramValidators) == 0 {
140 return nil
141 }
142
143 if len(h.paramValidators) != h.paramCount {
144 return ufmt.Errorf(
145 "validator count mismatch for %s: expected %d validator(s), got %d",
146 h.HandlerKey(), h.paramCount, len(h.paramValidators),
147 )
148 }
149
150 for i, validator := range h.paramValidators {
151 if validator == nil {
152 continue
153 }
154
155 if err := validator(params[i]); err != nil {
156 return ufmt.Errorf("param[%d]: %v", i, err)
157 }
158 }
159
160 return nil
161}
162
163// ParameterRegistry manages the collection of parameter handlers for governance execution.
164// This registry allows proposals to execute parameter changes across different system contracts.
165type ParameterRegistry struct {
166 handlers *avl.Tree // Tree storing handler configurations keyed by package:function
167}
168
169// register adds a new parameter handler to the registry.
170// Each handler is identified by a unique combination of package path and function name.
171//
172// Parameters:
173// - handler: parameter handler configuration to register
174func (r *ParameterRegistry) Register(handler ParameterHandlerOptions) {
175 r.handlers.Set(handler.HandlerKey(), handler)
176}
177
178// handler retrieves a parameter handler by package path and function name.
179// This method is used during proposal execution to find the appropriate handler.
180//
181// Parameters:
182// - pkgPath: package path of the target contract
183// - function: function name to be called
184//
185// Returns:
186// - ParameterHandler: the matching parameter handler
187// - error: error if handler not found or casting fails
188func (r *ParameterRegistry) Handler(key string) (ParameterHandler, error) {
189 // Retrieve handler from registry
190 h, exists := r.handlers.Get(key)
191 if !exists {
192 return nil, ufmt.Errorf("handler not found for %s", key)
193 }
194
195 // Cast to correct type
196 handler, ok := h.(ParameterHandlerOptions)
197 if !ok {
198 return nil, ufmt.Errorf("failed to cast handler %s to ParameterHandler", key)
199 }
200
201 return &handler, nil
202}
203
204// NewParameterRegistry creates a new empty parameter registry.
205//
206// Returns:
207// - *ParameterRegistry: new registry instance
208func NewParameterRegistry() *ParameterRegistry {
209 return &ParameterRegistry{handlers: avl.NewTree()}
210}
211
212// makeHandlerKey creates a unique identifier for a handler based on package path and function.
213//
214// Parameters:
215// - pkgPath: package path of the target contract
216// - function: function name to be called
217//
218// Returns:
219// - string: unique key in format "pkgPath:function"
220func makeHandlerKey(pkgPath, function string) string {
221 return pkgPath + ":" + function
222}
223
224// createParameterHandlers initializes and configures all supported parameter handlers.
225// This function defines all the parameter changes that can be executed through governance proposals.
226// It covers configuration changes for various system components including pools, staking, fees, etc.
227//
228// Returns:
229// - *ParameterRegistry: fully configured registry with all supported handlers
230func CreateParameterHandlers() *ParameterRegistry {
231 registry := NewParameterRegistry()
232
233 // Define all handler configurations for different system components
234 handlers := []*ParameterHandlerOptions{
235 // Community pool token transfers
236 {
237 pkgPath: COMMUNITY_POOL_PATH,
238 function: "TransferToken",
239 paramCount: 3,
240 paramValidators: []paramValidator{
241 stringValidator, // pkgPath
242 addressValidator, // to
243 numberValidator(kindInt64), // amount
244 },
245 handlerFunc: func(params []string) error {
246 // Transfer tokens from community pool to specified address
247 cp.TransferToken(
248 cross,
249 params[0], // pkgPath
250 address(params[1]), // to
251 parseNumber(params[2], kindInt64).(int64), // amount
252 )
253
254 return nil
255 },
256 },
257 // Emission distribution configuration
258 {
259 pkgPath: EMISSION_PATH,
260 function: "SetDistributionStartTime",
261 paramCount: 1,
262 paramValidators: []paramValidator{
263 numberValidator(kindInt64), // start time
264 },
265 handlerFunc: func(params []string) error {
266 // Set distribution start time
267 en.SetDistributionStartTime(cross, parseInt64(params[0]))
268
269 return nil
270 },
271 },
272 {
273 pkgPath: EMISSION_PATH,
274 function: "ChangeDistributionPct",
275 paramCount: 8,
276 paramValidators: []paramValidator{
277 numberValidator(kindInt), // target01
278 numberValidator(kindInt64), // pct01
279 numberValidator(kindInt), // target02
280 numberValidator(kindInt64), // pct02
281 numberValidator(kindInt), // target03
282 numberValidator(kindInt64), // pct03
283 numberValidator(kindInt), // target04
284 numberValidator(kindInt64), // pct04
285 },
286 handlerFunc: func(params []string) error {
287 // Parse distribution targets and percentages
288 target01 := parseNumber(params[0], kindInt).(int) // target01
289 pct01 := parseNumber(params[1], kindInt64).(int64) // pct01
290 target02 := parseNumber(params[2], kindInt).(int) // target02
291 pct02 := parseNumber(params[3], kindInt64).(int64) // pct02
292 target03 := parseNumber(params[4], kindInt).(int) // target03
293 pct03 := parseNumber(params[5], kindInt64).(int64) // pct03
294 target04 := parseNumber(params[6], kindInt).(int) // target04
295 pct04 := parseNumber(params[7], kindInt64).(int64) // pct04
296
297 // Update emission distribution percentages
298 en.ChangeDistributionPct(
299 cross,
300 target01, // target01
301 pct01, // pct01
302 target02, // target02
303 pct02, // pct02
304 target03, // target03
305 pct03, // pct03
306 target04, // target04
307 pct04, // pct04
308 )
309
310 return nil
311 },
312 },
313 // Governance configuration changes
314 {
315 pkgPath: GOV_GOVERNANCE_PATH,
316 function: "Reconfigure",
317 paramCount: 7,
318 paramValidators: []paramValidator{
319 numberValidator(kindInt64), // votingStartDelay
320 numberValidator(kindInt64), // votingPeriod
321 numberValidator(kindInt64), // votingWeightSmoothingDuration
322 numberValidator(kindInt64), // quorum
323 numberValidator(kindInt64), // proposalCreationThreshold
324 numberValidator(kindInt64), // executionDelay
325 numberValidator(kindInt64), // executionWindow
326 },
327 handlerFunc: func(params []string) error {
328 // Parse governance configuration parameters
329 votingStartDelay := parseInt64(params[0])
330 votingPeriod := parseInt64(params[1])
331 votingWeightSmoothingDuration := parseInt64(params[2])
332 quorum := parseInt64(params[3])
333 proposalCreationThreshold := parseInt64(params[4])
334 executionDelay := parseInt64(params[5])
335 executionWindow := parseInt64(params[6])
336
337 // Reconfigure governance parameters through governance process
338 governance.Reconfigure(
339 cross,
340 votingStartDelay,
341 votingPeriod,
342 votingWeightSmoothingDuration,
343 quorum,
344 proposalCreationThreshold,
345 executionDelay,
346 executionWindow,
347 )
348
349 return nil
350 },
351 },
352
353 // Pool protocol fee configuration
354 {
355 pkgPath: POOL_PATH,
356 function: "CollectProtocol",
357 paramCount: 6,
358 paramValidators: []paramValidator{
359 stringValidator, // token0Path
360 stringValidator, // token1Path
361 uint64Validator, // fee
362 addressValidator, // recipient
363 nil, // amount0Requested (validated in pool logic)
364 nil, // amount1Requested (validated in pool logic)
365 },
366 handlerFunc: func(params []string) error {
367 pl.CollectProtocol(
368 cross,
369 params[0], // token0Path
370 params[1], // token1Path
371 uint32(parseUint64(params[2])), // fee
372 address(params[3]), // recipient
373 params[4], // amount0Requested
374 params[5], // amount1Requested
375 )
376
377 return nil
378 },
379 },
380 {
381 pkgPath: POOL_PATH,
382 function: "SetFeeProtocol",
383 paramCount: 2,
384 paramValidators: []paramValidator{
385 uint8RangeValidator("feeProtocol0"),
386 uint8RangeValidator("feeProtocol1"),
387 },
388 handlerFunc: func(params []string) error {
389 // Parse and validate fee protocol values
390 feeProtocol0 := parseInt64(params[0])
391 feeProtocol1 := parseInt64(params[1])
392
393 // Validate fee protocol values are within uint8 range
394 if feeProtocol0 > 255 {
395 panic(ufmt.Sprintf("feeProtocol0 out of range: %d", feeProtocol0))
396 }
397
398 if feeProtocol1 > 255 {
399 panic(ufmt.Sprintf("feeProtocol1 out of range: %d", feeProtocol1))
400 }
401
402 // Set protocol fee percentages
403 pl.SetFeeProtocol(
404 cross,
405 uint8(feeProtocol0), // feeProtocol0
406 uint8(feeProtocol1), // feeProtocol1
407 )
408
409 return nil
410 },
411 },
412 // Pool creation fee
413 {
414 pkgPath: POOL_PATH,
415 function: "SetPoolCreationFee",
416 paramCount: 1,
417 paramValidators: []paramValidator{
418 numberValidator(kindInt64), // fee
419 },
420 handlerFunc: func(params []string) error {
421 // Set fee required to create new pools
422 pl.SetPoolCreationFee(cross, parseInt64(params[0])) // fee
423 return nil
424 },
425 },
426 // Pool withdrawal fee
427 {
428 pkgPath: POOL_PATH,
429 function: "SetWithdrawalFee",
430 paramCount: 1,
431 paramValidators: []paramValidator{
432 uint64Validator, // fee
433 },
434 handlerFunc: func(params []string) error {
435 // Set fee for withdrawing from pools
436 pl.SetWithdrawalFee(cross, parseUint64(params[0])) // fee
437 return nil
438 },
439 },
440
441 // Protocol fee distribution
442 {
443 pkgPath: PROTOCOL_FEE_PATH,
444 function: "SetDevOpsPct",
445 paramCount: 1,
446 paramValidators: []paramValidator{
447 numberValidator(kindInt64), // pct
448 },
449 handlerFunc: func(params []string) error {
450 // Set percentage of protocol fees going to development operations
451 pf.SetDevOpsPct(cross, parseInt64(params[0])) // pct
452 return nil
453 },
454 },
455
456 // Router swap fee
457 {
458 pkgPath: ROUTER_PATH,
459 function: "SetSwapFee",
460 paramCount: 1,
461 paramValidators: []paramValidator{
462 uint64Validator, // fee
463 },
464 handlerFunc: func(params []string) error {
465 // Set fee charged for token swaps
466 rr.SetSwapFee(cross, parseUint64(params[0])) // fee
467 return nil
468 },
469 },
470
471 // Staker configuration handlers
472 {
473 pkgPath: STAKER_PATH,
474 function: "SetDepositGnsAmount",
475 paramCount: 1,
476 paramValidators: []paramValidator{
477 numberValidator(kindInt64), // amount
478 },
479 handlerFunc: func(params []string) error {
480 // Set minimum GNS amount required for staking deposits
481 sr.SetDepositGnsAmount(cross, parseInt64(params[0])) // amount
482 return nil
483 },
484 },
485 {
486 pkgPath: STAKER_PATH,
487 function: "SetMinimumRewardAmount",
488 paramCount: 1,
489 paramValidators: []paramValidator{
490 numberValidator(kindInt64), // amount
491 },
492 handlerFunc: func(params []string) error {
493 // Set minimum GNS amount required for staking deposits
494 sr.SetMinimumRewardAmount(cross, parseInt64(params[0])) // amount
495 return nil
496 },
497 },
498 {
499 pkgPath: STAKER_PATH,
500 function: "SetTokenMinimumRewardAmount",
501 paramCount: 1,
502 paramValidators: []paramValidator{
503 stringValidator, // tokenPath:amount
504 },
505 handlerFunc: func(params []string) error {
506 // Set minimum GNS amount required for staking deposits
507 // params[0] is a string in the format "tokenPath:amount"
508 sr.SetTokenMinimumRewardAmount(cross, params[0]) // amount
509 return nil
510 },
511 },
512 {
513 pkgPath: STAKER_PATH,
514 function: "SetPoolTier",
515 paramCount: 2,
516 paramValidators: []paramValidator{
517 stringValidator, // pool
518 uint64Validator, // tier
519 },
520 handlerFunc: func(params []string) error {
521 // Assign tier level to a specific pool
522 sr.SetPoolTier(
523 cross,
524 params[0], // pool
525 parseUint64(params[1]), // tier
526 )
527 return nil
528 },
529 },
530 {
531 pkgPath: STAKER_PATH,
532 function: "ChangePoolTier",
533 paramCount: 2,
534 paramValidators: []paramValidator{
535 stringValidator, // pool
536 uint64Validator, // tier
537 },
538 handlerFunc: func(params []string) error {
539 // Change existing pool's tier level
540 sr.ChangePoolTier(
541 cross,
542 params[0], // pool
543 parseUint64(params[1]), // tier
544 )
545 return nil
546 },
547 },
548 {
549 pkgPath: STAKER_PATH,
550 function: "RemovePoolTier",
551 paramCount: 1,
552 paramValidators: []paramValidator{
553 stringValidator, // pool
554 },
555 handlerFunc: func(params []string) error {
556 // Remove tier assignment from a pool
557 sr.RemovePoolTier(cross, params[0]) // pool
558 return nil
559 },
560 },
561 {
562 pkgPath: STAKER_PATH,
563 function: "SetUnStakingFee",
564 paramCount: 1,
565 paramValidators: []paramValidator{
566 numberValidator(kindInt64), // fee
567 },
568 handlerFunc: func(params []string) error {
569 // Set fee charged for unstaking operations
570 fee := parseInt64(params[0])
571 sr.SetUnStakingFee(cross, fee)
572 return nil
573 },
574 },
575 {
576 pkgPath: STAKER_PATH,
577 function: "SetWarmUp",
578 paramCount: 2,
579 paramValidators: []paramValidator{
580 numberValidator(kindInt64), // percent
581 numberValidator(kindInt64), // block
582 },
583 handlerFunc: func(params []string) error {
584 // Set warm-up period configuration for staking
585 percent := parseInt64(params[0])
586 block := parseNumber(params[1], kindInt64).(int64)
587 sr.SetWarmUp(cross, percent, block)
588
589 return nil
590 },
591 },
592
593 // System halt controls
594 {
595 pkgPath: HALT_PATH,
596 function: "SetHaltLevel",
597 paramCount: 1,
598 paramValidators: []paramValidator{
599 stringValidator, // halt level string
600 },
601 handlerFunc: func(params []string) error {
602 // Set system-wide halt status
603 halt.SetHaltLevel(cross, halt.HaltLevel(params[0])) // true = halt, false = no halt
604
605 return nil
606 },
607 },
608 {
609 pkgPath: HALT_PATH,
610 function: "SetOperationStatus",
611 paramCount: 2,
612 paramValidators: []paramValidator{
613 stringValidator, // opType
614 boolValidator, // allowed
615 },
616 handlerFunc: func(params []string) error {
617 // Enable or disable specific operation types
618 opType := halt.OpType(params[0])
619 allowed := parseBool(params[1])
620
621 halt.SetOperationStatus(cross, opType, allowed)
622
623 return nil
624 },
625 },
626
627 // RBAC configuration
628 {
629 pkgPath: RBAC_PATH,
630 function: "RegisterRole",
631 paramCount: 2,
632 paramValidators: []paramValidator{
633 stringValidator, // roleName
634 addressValidator, // roleAddress
635 },
636 handlerFunc: func(params []string) error {
637 roleName := params[0]
638 roleAddress := address(params[1])
639
640 // Register a new role
641 rbac.RegisterRole(cross, roleName, roleAddress)
642
643 return nil
644 },
645 },
646 {
647 pkgPath: RBAC_PATH,
648 function: "UpdateRoleAddress",
649 paramCount: 2,
650 paramValidators: []paramValidator{
651 stringValidator, // roleName
652 addressValidator, // roleAddress
653 },
654 handlerFunc: func(params []string) error {
655 roleName := params[0]
656 roleAddress := address(params[1])
657
658 // Update role address
659 rbac.UpdateRoleAddress(cross, roleName, roleAddress)
660
661 return nil
662 },
663 },
664 {
665 pkgPath: RBAC_PATH,
666 function: "RemoveRole",
667 paramCount: 1,
668 paramValidators: []paramValidator{
669 stringValidator, // roleName
670 },
671 handlerFunc: func(params []string) error {
672 roleName := params[0]
673
674 // Remove role
675 rbac.RemoveRole(cross, roleName)
676
677 return nil
678 },
679 },
680
681 // Protocol fee - SetGovStakerPct
682 {
683 pkgPath: PROTOCOL_FEE_PATH,
684 function: "SetGovStakerPct",
685 paramCount: 1,
686 paramValidators: []paramValidator{
687 numberValidator(kindInt64), // pct
688 },
689 handlerFunc: func(params []string) error {
690 // Set percentage of protocol fees going to governance stakers
691 pf.SetGovStakerPct(cross, parseInt64(params[0])) // pct
692 return nil
693 },
694 },
695
696 // Staker - Token list management
697 {
698 pkgPath: STAKER_PATH,
699 function: "AddToken",
700 paramCount: 1,
701 paramValidators: []paramValidator{
702 stringValidator, // tokenPath
703 },
704 handlerFunc: func(params []string) error {
705 // Add token to allowed token list for external incentives
706 sr.AddToken(cross, params[0]) // tokenPath
707 return nil
708 },
709 },
710 {
711 pkgPath: STAKER_PATH,
712 function: "RemoveToken",
713 paramCount: 1,
714 paramValidators: []paramValidator{
715 stringValidator, // tokenPath
716 },
717 handlerFunc: func(params []string) error {
718 // Remove token from allowed token list
719 sr.RemoveToken(cross, params[0]) // tokenPath
720 return nil
721 },
722 },
723
724 // Launchpad - Project management
725 {
726 pkgPath: LAUNCHPAD_PATH,
727 function: "CreateProject",
728 paramCount: 10,
729 paramValidators: []paramValidator{
730 stringValidator, // name
731 stringValidator, // tokenPath
732 addressValidator, // recipient
733 numberValidator(kindInt64), // depositAmount
734 stringValidator, // conditionTokens
735 stringValidator, // conditionAmounts
736 numberValidator(kindInt64), // tier30Ratio
737 numberValidator(kindInt64), // tier90Ratio
738 numberValidator(kindInt64), // tier180Ratio
739 numberValidator(kindInt64), // startTime
740 },
741 handlerFunc: func(params []string) error {
742 // Create a new launchpad project
743 lp.CreateProject(
744 cross,
745 params[0], // name
746 params[1], // tokenPath
747 address(params[2]), // recipient
748 parseNumber(params[3], kindInt64).(int64), // depositAmount
749 params[4], // conditionTokens
750 params[5], // conditionAmounts
751 parseNumber(params[6], kindInt64).(int64), // tier30Ratio
752 parseNumber(params[7], kindInt64).(int64), // tier90Ratio
753 parseNumber(params[8], kindInt64).(int64), // tier180Ratio
754 parseNumber(params[9], kindInt64).(int64), // startTime
755 )
756 return nil
757 },
758 },
759 // Upgrade handlers for various domains
760 {
761 pkgPath: POOL_PATH,
762 function: "UpgradeImpl",
763 paramCount: 1,
764 paramValidators: []paramValidator{
765 stringValidator, // packagePath
766 },
767 handlerFunc: func(params []string) error {
768 // Upgrade pool implementation
769 pl.UpgradeImpl(cross, params[0]) // packagePath
770 return nil
771 },
772 },
773 {
774 pkgPath: POSITION_PATH,
775 function: "UpgradeImpl",
776 paramCount: 1,
777 paramValidators: []paramValidator{
778 stringValidator, // packagePath
779 },
780 handlerFunc: func(params []string) error {
781 // Upgrade position implementation
782 pos.UpgradeImpl(cross, params[0]) // packagePath
783 return nil
784 },
785 },
786 {
787 pkgPath: STAKER_PATH,
788 function: "UpgradeImpl",
789 paramCount: 1,
790 paramValidators: []paramValidator{
791 stringValidator, // packagePath
792 },
793 handlerFunc: func(params []string) error {
794 // Upgrade staker implementation
795 sr.UpgradeImpl(cross, params[0]) // packagePath
796 return nil
797 },
798 },
799 {
800 pkgPath: LAUNCHPAD_PATH,
801 function: "UpgradeImpl",
802 paramCount: 1,
803 paramValidators: []paramValidator{
804 stringValidator, // packagePath
805 },
806 handlerFunc: func(params []string) error {
807 // Upgrade launchpad implementation
808 lp.UpgradeImpl(cross, params[0]) // packagePath
809 return nil
810 },
811 },
812 {
813 pkgPath: GOV_GOVERNANCE_PATH,
814 function: "UpgradeImpl",
815 paramCount: 1,
816 paramValidators: []paramValidator{
817 stringValidator, // targetPackagePath
818 },
819 handlerFunc: func(params []string) error {
820 // Upgrade governance implementation
821 governance.UpgradeImpl(cross, params[0]) // packagePath
822 return nil
823 },
824 },
825 {
826 pkgPath: GOV_STAKER_PATH,
827 function: "UpgradeImpl",
828 paramCount: 1,
829 paramValidators: []paramValidator{
830 stringValidator, // packagePath
831 },
832 handlerFunc: func(params []string) error {
833 // Upgrade gov staker implementation
834 gs.UpgradeImpl(cross, params[0]) // packagePath
835 return nil
836 },
837 },
838 {
839 pkgPath: ROUTER_PATH,
840 function: "UpgradeImpl",
841 paramCount: 1,
842 paramValidators: []paramValidator{
843 stringValidator, // packagePath
844 },
845 handlerFunc: func(params []string) error {
846 // Upgrade router implementation
847 rr.UpgradeImpl(cross, params[0]) // packagePath
848 return nil
849 },
850 },
851 {
852 pkgPath: PROTOCOL_FEE_PATH,
853 function: "UpgradeImpl",
854 paramCount: 1,
855 paramValidators: []paramValidator{
856 stringValidator, // packagePath
857 },
858 handlerFunc: func(params []string) error {
859 // Upgrade protocol fee implementation
860 pf.UpgradeImpl(cross, params[0]) // packagePath
861 return nil
862 },
863 },
864 }
865
866 // Register all configured handlers in the registry
867 registerHandlers(registry, handlers)
868
869 return registry
870}
871
872// registerHandlers batch registers all configured handlers into the registry.
873// This helper function processes the handler configuration array and adds each handler to the registry.
874//
875// Parameters:
876// - registry: the parameter registry to add handlers to
877// - handlerOptions: slice of handler configurations to register
878func registerHandlers(registry *ParameterRegistry, handlerOptions []*ParameterHandlerOptions) {
879 for _, handlerOption := range handlerOptions {
880 registry.Register(*handlerOption)
881 }
882}
883
884// runValidator executes a validator function and converts panics to errors.
885func runValidator(fn func()) (err error) {
886 defer func() {
887 if r := recover(); r != nil {
888 if e, ok := r.(error); ok {
889 err = e
890 return
891 }
892 err = ufmt.Errorf("%v", r)
893 }
894 }()
895
896 fn()
897 return nil
898}
899
900// Basic reusable validators for proposal-time type checking.
901var (
902 stringValidator = func(s string) error {
903 return nil
904 }
905 boolValidator = func(s string) error {
906 return runValidator(func() {
907 parseBool(s)
908 })
909 }
910 uint64Validator = func(s string) error {
911 return runValidator(func() {
912 parseUint64(s)
913 })
914 }
915 addressValidator = func(s string) error {
916 // allow zero address
917 if s == "" {
918 return nil
919 }
920 return runValidator(func() {
921 addr := address(s)
922 if !addr.IsValid() {
923 panic(ufmt.Sprintf("invalid address: %s", addr))
924 }
925 })
926 }
927)
928
929func numberValidator(kind numberKind) paramValidator {
930 return func(s string) error {
931 return runValidator(func() {
932 parseNumber(s, kind)
933 })
934 }
935}
936
937func uint8RangeValidator(name string) paramValidator {
938 return func(s string) error {
939 return runValidator(func() {
940 value := parseInt64(s)
941 if value < 0 || value > 255 {
942 panic(ufmt.Sprintf("%s out of range: %d", name, value))
943 }
944 })
945 }
946}
947
948// validateExecutions validates that all executions in a parameter change proposal
949// correspond to registered handlers in the global parameter registry.
950// This function performs comprehensive validation including:
951// - Basic format validation (count, structure)
952// - Handler existence verification in the registry
953// - Parameter count validation against handler expectations
954//
955// Parameters:
956// - numToExecute: number of parameter changes to execute
957// - executions: encoded execution string with parameter changes
958//
959// Returns:
960// - error: validation error if any execution is invalid
961func validateExecutions(numToExecute int64, executions string) error {
962 // Validate execution count is positive
963 if numToExecute <= 0 {
964 return makeErrorWithDetails(
965 errInvalidInput,
966 "numToExecute is less than or equal to 0",
967 )
968 }
969
970 // Check if executions string is empty
971 if executions == "" {
972 return makeErrorWithDetails(
973 errInvalidInput,
974 "executions is empty",
975 )
976 }
977
978 // Split execution string into individual messages
979 msgs := strings.Split(executions, messageSeparator)
980 msgCount := len(msgs)
981
982 // Validate execution count matches message count
983 if msgCount != int(numToExecute) {
984 return makeErrorWithDetails(
985 errInvalidInput,
986 ufmt.Sprintf("executions count (%d) does not match numToExecute (%d)", len(msgs), numToExecute),
987 )
988 }
989
990 // Validate execution count doesn't exceed maximum
991 if numToExecute > maxNumberOfExecution {
992 return makeErrorWithDetails(
993 errInvalidInput,
994 ufmt.Sprintf("numToExecute is greater than %d", maxNumberOfExecution),
995 )
996 }
997
998 // Parse and validate each execution message
999 for i, msg := range msgs {
1000 // Split message into components: pkgPath, function, params
1001 parts := strings.Split(msg, parameterSeparator)
1002 if len(parts) != 3 {
1003 // Provide more helpful error message based on what's wrong
1004 detail := ufmt.Sprintf("execution[%d]: expected 3 parts (pkgPath, function, params), got %d", i, len(parts))
1005 return makeErrorWithDetails(
1006 errInvalidMessageFormat,
1007 detail,
1008 )
1009 }
1010
1011 pkgPath := parts[0]
1012 function := parts[1]
1013 paramStr := parts[2]
1014
1015 // Validate package path and function are not empty
1016 if pkgPath == "" {
1017 return makeErrorWithDetails(
1018 errInvalidInput,
1019 ufmt.Sprintf("execution[%d]: package path is empty", i),
1020 )
1021 }
1022
1023 if function == "" {
1024 return makeErrorWithDetails(
1025 errInvalidInput,
1026 ufmt.Sprintf("execution[%d]: function name is empty", i),
1027 )
1028 }
1029
1030 // Check if handler exists in registry
1031 key := makeHandlerKey(pkgPath, function)
1032 handler, err := globalParameterRegistry.Handler(key)
1033 if err != nil {
1034 return makeErrorWithDetails(
1035 errInvalidExecution,
1036 ufmt.Sprintf("execution[%d]: %s (key: %s)", i, err.Error(), key),
1037 )
1038 }
1039
1040 // Validate parameter count matches handler's expected count
1041 params := []string{}
1042 if paramStr != "" {
1043 params = strings.Split(paramStr, ",")
1044 }
1045
1046 // Get expected parameter count from handler
1047 handlerOpts, ok := handler.(*ParameterHandlerOptions)
1048 if !ok {
1049 return makeErrorWithDetails(
1050 errInvalidExecution,
1051 ufmt.Sprintf("execution[%d]: failed to get handler options", i),
1052 )
1053 }
1054
1055 // Validate parameter types/format ahead of proposal creation
1056 if err := handlerOpts.ValidateParams(params); err != nil {
1057 return makeErrorWithDetails(
1058 errInvalidInput,
1059 ufmt.Sprintf("execution[%d]: %v", i, err),
1060 )
1061 }
1062 }
1063
1064 return nil
1065}