---
# System prepended metadata

title: Dynamic bounded parameter config with basic validation check

---

# Dynamic bounded parameter config with basic validation check

Current there're two kind of config:
- runtime constant value: default fixed value
- pallet storage variable: dynamic value update by dispatch call

I'm trying to union all these two types, and given support some basic validation, for example, the value should match [min, max]. and if set parameter out of range, there'll be error. for the sake of simplicity, we say that `root` are responsible for set parameter bound info, and `admin` are responsible for set parameter value.

## Basic Workflow

1. `root` set parameter bound info
2. `admin` set parameter value, the value should within range of bound info

## Draft design

- Single Key, Global Key
  - aim to replace runtime fixed config item
  - primitives/config: ConfigKey + ConfigValue
- Multiple Key, Composable Key
  - aim to replace pallet storage config item
  - different module has different Concrete Config struct/enum
    - enum XXXConfigKey 
    - struct XXXConfig

### Common

BoundType for different types:
```rust
struct BoundBalance|BoundRate|BoundBlockNumber {
    enable: bool,
    val: Option<Balance/Rate/BlockNumber>,
    min: Option<Balance/Rate/BlockNumber>,
    max: Option<Balance/Rate/BlockNumber>,
}
```

> the reason of `enable` field is given later.

### GlobalKey

ConfigKey will list all runtime related config item:

```rust=
enum ConfigKey {
    // config key for module_incentives
    AccumulatePeriod,
    EarnShareBooster,
    ...
}
```

and `root` can also change the value by onchain dispatch call.

### Module definition
different module has concreate config, i.e. for module_incentives.

first, list all config key type of this specific module.

```rust=
enum IncentiveConfigKeyType {
    IncentiveRewardAmount,
    DexSavingRewardRate,
    ClaimRewardDeductionRate,
}
```

then, define the config key and value of this module.

```rust=
struct IncentiveConfigKey<PoolId, CurrencyId> {
    key_name: IncentiveConfigKeyType,
    pool_id: PoolId,
    currency_id: Option<CurrencyId>,
}

struct IncentiveConfigValue<Balance, Rate> {
    reward_amount: Option<BoundBalance>,
    dex_saving_reward_rate: Option<BoundRate>,
    claim_reward_deducdtion_rate: Option<BoundRate>,
}
```

### pre-set parameter bounded info

before change/set parameter for pallet, there should exist parameter bound info. both these two steps are invoke same dispatch call but in different process. 

after root set bound info, example data like:

|IncentiveConfigKeyType|pool_id|currency_id|value|
|----------------------|-------|-----------|-----|
|IncentiveRewardAmount|pool_id: 0|currency_id: KAR|BoundBalance(None, **1, 3**)|
|IncentiveRewardAmount|pool_id: 0|currency_id: KBTC|BoundBalance(None, **1, 5**)|
|IncentiveRewardAmount|pool_id: 1|currency_id: KAR|BoundBalance(None, **1, 5**)|
|IncentiveRewardAmount|pool_id: 1|currency_id: BNC|BoundBalance(None, **10, 30**)|
|DexSavingRewardRate|pool_id: 0|-|BoundRate(None, 0.01, 0.03)
|ClaimRewardDeductionRate|pool_id: 0|-|BoundRate(None, 0.1, 0.3)


### change parameter value

when update pallet parameter config, the first step is validation. for example, in module_incentive, admin call `update_dex_saving_rewards(pool_id, rate)` for dex pool: `(kUSD, kBTC)`:

- check that given `rate` is in range of bound info.
- *do some extra special validation...*

example data after admin set parameter value:

|IncentiveConfigKeyType|pool_id|currency_id|value|
|----------------------|-------|-----------|-----|
|IncentiveRewardAmount|pool_id: 0|currency_id: KAR|BoundBalance(**2**, 1, 3)|
|IncentiveRewardAmount|pool_id: 0|currency_id: KBTC|BoundBalance(**3**, 1, 5)|
|IncentiveRewardAmount|pool_id: 1|currency_id: KAR|BoundBalance(**2**, 1, 5)|
|IncentiveRewardAmount|pool_id: 1|currency_id: BNC|BoundBalance(**20**, 10, 30)|
|DexSavingRewardRate|pool_id: 0|-|BoundRate(**0.02**, 0.01, 0.03)
|ClaimRewardDeductionRate|pool_id: 0|-|BoundRate(**0.2**, 0.1, 0.3)


### extra work tbd(discuss)

1. We can also introduce some extra work to make parameter truly take effect. that's why `BoundBalance` has a field called `enabled`. but whether it's worthy or not can be discussed.

2. we can move the dispatch call to a unified pallet(maybe called `configs`?), and also provide some hook for *extra special validation*.


### comments

1. over design?