Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}