mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-20 15:05:21 +00:00
feat(x/cdp): update begin bloocker to run liquidations every X blocks based off params (#1818)
* (feat) update x/cdp to run every X blocks based off params (#1814)
* add new cdp module param to protonet genesis
* update cdp / cdp related tests for new module param
* update telemetry docs and setup for collecting against local node
* update kvool commit for new cdp param
(cherry picked from commit 4d62f47773
)
* add tests for configurable x/cdp begin blocker interval param
add migration for default value of param
* make adjustments based off pr feedback
* fix proto back compat check
This commit is contained in:
parent
2bccb6deaf
commit
c59a491788
@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
### Features
|
||||
|
||||
- (cli) [#1785] Add `shard` CLI command to support creating partitions of data for standalone nodes
|
||||
- (cdp) [#1818] Add module param and logic for running x/cdp begin blocker every `n` blocks
|
||||
- (cli) [#1804] Add `rocksdb compact` command for manual DB compaction of state or blockstore.
|
||||
|
||||
## [v0.25.0]
|
||||
@ -69,6 +70,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
## [v0.24.3]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- (deps) [#1770] Bump ledger-cosmos-go to v0.13.1 to resolve signing error with
|
||||
- (rocksdb) [#1767] Fix resolution of rocksdb database path introduced in v0.24.2
|
||||
|
||||
@ -324,7 +326,6 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
|
||||
[#1804]: https://github.com/Kava-Labs/kava/pull/1804
|
||||
[#1785]: https://github.com/Kava-Labs/kava/pull/1785
|
||||
[#1784]: https://github.com/Kava-Labs/kava/pull/1784
|
||||
[#1776]: https://github.com/Kava-Labs/kava/pull/1776
|
||||
[#1770]: https://github.com/Kava-Labs/kava/pull/1770
|
||||
[#1755]: https://github.com/Kava-Labs/kava/pull/1755
|
||||
[#1761]: https://github.com/Kava-Labs/kava/pull/1761
|
||||
@ -384,7 +385,6 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
|
||||
[v0.24.1]: https://github.com/Kava-Labs/kava/compare/v0.24.1...v0.24.0
|
||||
[v0.24.0]: https://github.com/Kava-Labs/kava/compare/v0.24.0...v0.23.2
|
||||
[v0.23.2]: https://github.com/Kava-Labs/kava/compare/v0.23.1...v0.23.2
|
||||
[v0.23.1]: https://github.com/Kava-Labs/kava/compare/v0.23.0...v0.23.1
|
||||
[v0.23.0]: https://github.com/Kava-Labs/kava/compare/v0.21.1...v0.23.0
|
||||
[v0.16.1]: https://github.com/Kava-Labs/kava/compare/v0.16.0...v0.16.1
|
||||
[v0.16.0]: https://github.com/Kava-Labs/kava/compare/v0.15.2...v0.16.0
|
||||
|
1
Makefile
1
Makefile
@ -330,6 +330,7 @@ start-remote-sims:
|
||||
-—container-override environment=[{SIM_NAME=master-$(VERSION)}]
|
||||
|
||||
update-kvtool:
|
||||
git submodule init || true
|
||||
git submodule update
|
||||
cd tests/e2e/kvtool && make install
|
||||
|
||||
|
1
ci/env/kava-protonet/genesis.json
vendored
1
ci/env/kava-protonet/genesis.json
vendored
@ -837,6 +837,7 @@
|
||||
"gov_denom": "ukava",
|
||||
"params": {
|
||||
"circuit_breaker": false,
|
||||
"liquidation_block_interval": 500,
|
||||
"collateral_params": [
|
||||
{
|
||||
"auction_size": "50000000000",
|
||||
|
@ -3505,6 +3505,9 @@ paths:
|
||||
type: string
|
||||
circuit_breaker:
|
||||
type: boolean
|
||||
liquidation_block_interval:
|
||||
type: string
|
||||
format: int64
|
||||
description: Params defines the parameters for the cdp module.
|
||||
description: >-
|
||||
QueryParamsResponse defines the response type for the Query/Params
|
||||
@ -51628,6 +51631,9 @@ definitions:
|
||||
type: string
|
||||
circuit_breaker:
|
||||
type: boolean
|
||||
liquidation_block_interval:
|
||||
type: string
|
||||
format: int64
|
||||
description: Params defines the parameters for the cdp module.
|
||||
kava.cdp.v1beta1.QueryAccountsResponse:
|
||||
type: object
|
||||
@ -52161,6 +52167,9 @@ definitions:
|
||||
type: string
|
||||
circuit_breaker:
|
||||
type: boolean
|
||||
liquidation_block_interval:
|
||||
type: string
|
||||
format: int64
|
||||
description: Params defines the parameters for the cdp module.
|
||||
description: >-
|
||||
QueryParamsResponse defines the response type for the Query/Params RPC
|
||||
|
@ -38,10 +38,10 @@ Then restart the service with the updated settings
|
||||
|
||||
## Running local prometheus collector and grafana services
|
||||
|
||||
To collect app metrics and visualize them locally, you can run the prometheus collector and grafana services with docker compose from the repo root directory
|
||||
To collect app metrics and visualize them locally, you can run the prometheus collector and grafana services with docker compose from the repo root directory (after updating `config.toml` and `app.toml` as detailed above)
|
||||
|
||||
```bash
|
||||
docker compose -f prometheus.docker-compose.yml
|
||||
docker compose -f prometheus.docker-compose.yml up
|
||||
```
|
||||
|
||||
Navigate to localhost:3000 to view the grafana unix
|
||||
@ -54,13 +54,13 @@ See [grafana docs](https://grafana.com/docs/grafana/latest/dashboards/) for info
|
||||
|
||||
### Collecting from local host
|
||||
|
||||
Update [prometheus config](../prometheus.yml) to collect metrics from your local source
|
||||
Update [prometheus config](../prometheus.yml) to collect metrics from your local source, where the port matches the value set for `config.toml/instrumentation.prometheus_listen_addr`
|
||||
|
||||
```yaml
|
||||
metrics_path: /
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost:8888
|
||||
- docker-host:8888
|
||||
```
|
||||
|
||||
### Collecting from remote host
|
||||
|
@ -1681,6 +1681,7 @@ Params defines the parameters for the cdp module.
|
||||
| `debt_auction_threshold` | [string](#string) | | |
|
||||
| `debt_auction_lot` | [string](#string) | | |
|
||||
| `circuit_breaker` | [bool](#bool) | | |
|
||||
| `liquidation_block_interval` | [int64](#int64) | | |
|
||||
|
||||
|
||||
|
||||
|
@ -34,3 +34,10 @@ services:
|
||||
- 9090
|
||||
networks:
|
||||
- monitoring
|
||||
docker-host:
|
||||
image: qoomon/docker-host
|
||||
cap_add: [ 'NET_ADMIN', 'NET_RAW' ]
|
||||
mem_limit: 8M
|
||||
restart: on-failure
|
||||
networks:
|
||||
- monitoring
|
||||
|
@ -3,8 +3,7 @@ global:
|
||||
evaluation_interval: 15s
|
||||
scrape_configs:
|
||||
- job_name: proxy
|
||||
scheme: https
|
||||
metrics_path: /
|
||||
static_configs:
|
||||
- targets:
|
||||
- 4efb-18-207-102-158.ngrok-free.app
|
||||
- docker-host:8888
|
||||
|
@ -66,6 +66,8 @@ message Params {
|
||||
(gogoproto.nullable) = false
|
||||
];
|
||||
bool circuit_breaker = 8;
|
||||
|
||||
int64 liquidation_block_interval = 9;
|
||||
}
|
||||
|
||||
// DebtParam defines governance params for debt assets
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit e1085562d203fd81c5dd8576170b29715b2de9ef
|
||||
Subproject commit 99214e8b5196b9ab16fa9902f956858c178921a5
|
@ -2,6 +2,7 @@ package cdp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/telemetry"
|
||||
@ -20,6 +21,9 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper)
|
||||
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
// only run CDP liquidations every `LiquidationBlockInterval` blocks
|
||||
skipSyncronizeAndLiquidations := ctx.BlockHeight()%params.LiquidationBlockInterval != 0
|
||||
|
||||
for _, cp := range params.CollateralParams {
|
||||
ok := k.UpdatePricefeedStatus(ctx, cp.SpotMarketID)
|
||||
if !ok {
|
||||
@ -36,6 +40,13 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if skipSyncronizeAndLiquidations {
|
||||
ctx.Logger().Debug(fmt.Sprintf("skipping x/cdp SynchronizeInterestForRiskyCDPs and LiquidateCdps for %s", cp.Type))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Logger().Debug(fmt.Sprintf("running x/cdp SynchronizeInterestForRiskyCDPs and LiquidateCdps for %s", cp.Type))
|
||||
|
||||
err = k.SynchronizeInterestForRiskyCDPs(ctx, cp.CheckCollateralizationIndexCount, sdk.MaxSortableDec, cp.Type)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -79,10 +79,13 @@ func (suite *ModuleTestSuite) createCdps() {
|
||||
suite.app = tApp
|
||||
suite.keeper = tApp.GetCDPKeeper()
|
||||
|
||||
// create 100 cdps
|
||||
for j := 0; j < 100; j++ {
|
||||
// 50 of the cdps will be collateralized with xrp
|
||||
collateral := "xrp"
|
||||
amount := 10000000000
|
||||
debt := simulation.RandIntBetween(rand.New(rand.NewSource(int64(j))), 750000000, 1249000000)
|
||||
// the other half (50) will be collateralized with btc
|
||||
if j%2 == 0 {
|
||||
collateral = "btc"
|
||||
amount = 100000000
|
||||
@ -122,37 +125,81 @@ func (suite *ModuleTestSuite) setPrice(price sdk.Dec, market string) {
|
||||
}
|
||||
|
||||
func (suite *ModuleTestSuite) TestBeginBlock() {
|
||||
// test setup, creating
|
||||
// 50 xrp cdps each with
|
||||
// collateral: 10000000000
|
||||
// debt: between 750000000 - 1249000000
|
||||
// if debt above 10000000000,
|
||||
// cdp added to tracker / liquidation list
|
||||
// debt total added to trackers debt total
|
||||
// 50 btc cdps each with
|
||||
// collateral: 10000000000
|
||||
// debt: between 2700000000 - 5332000000
|
||||
// if debt above 4000000000,
|
||||
// cdp added to tracker / liquidation list
|
||||
// debt total added to trackers debt total
|
||||
|
||||
// naively we expect roughly half of the cdps to be above the debt tracking floor, roughly 25 of them collaterallized with xrp, the other 25 with btcb
|
||||
|
||||
// usdx is the principal for all cdps
|
||||
suite.createCdps()
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
bk := suite.app.GetBankKeeper()
|
||||
|
||||
// test case 1 setup
|
||||
acc := ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
// track how much xrp collateral exists in the cdp module
|
||||
originalXrpCollateral := bk.GetBalance(suite.ctx, acc.GetAddress(), "xrp").Amount
|
||||
// set the trading price for xrp:usd pools
|
||||
suite.setPrice(d("0.2"), "xrp:usd")
|
||||
|
||||
// test case 1 execution
|
||||
cdp.BeginBlocker(suite.ctx, abci.RequestBeginBlock{Header: suite.ctx.BlockHeader()}, suite.keeper)
|
||||
|
||||
// test case 1 assert
|
||||
acc = ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
// get the current amount of xrp held by the cdp module
|
||||
finalXrpCollateral := bk.GetBalance(suite.ctx, acc.GetAddress(), "xrp").Amount
|
||||
seizedXrpCollateral := originalXrpCollateral.Sub(finalXrpCollateral)
|
||||
// calculate the number of cdps that were liquidated based on the total
|
||||
// seized collateral divided by the size of each cdp when it was created
|
||||
xrpLiquidations := int(seizedXrpCollateral.Quo(i(10000000000)).Int64())
|
||||
// should be 10 because...?
|
||||
suite.Equal(10, xrpLiquidations)
|
||||
|
||||
// btc collateral test case setup
|
||||
acc = ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
originalBtcCollateral := bk.GetBalance(suite.ctx, acc.GetAddress(), "btc").Amount
|
||||
// set the trading price for btc:usd pools
|
||||
suite.setPrice(d("6000"), "btc:usd")
|
||||
|
||||
// btc collateral test case execution
|
||||
cdp.BeginBlocker(suite.ctx, abci.RequestBeginBlock{Header: suite.ctx.BlockHeader()}, suite.keeper)
|
||||
|
||||
// btc collateral test case assertion 1
|
||||
acc = ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
finalBtcCollateral := bk.GetBalance(suite.ctx, acc.GetAddress(), "btc").Amount
|
||||
seizedBtcCollateral := originalBtcCollateral.Sub(finalBtcCollateral)
|
||||
// calculate the number of btc cdps that were liquidated based on the
|
||||
// total seized collateral divided by the fixed size of each cdp
|
||||
// when it was created during test setup
|
||||
btcLiquidations := int(seizedBtcCollateral.Quo(i(100000000)).Int64())
|
||||
suite.Equal(10, btcLiquidations)
|
||||
|
||||
// btc collateral test case assertion 2
|
||||
// test that the auction module has a balance equal to the amount of collateral seized
|
||||
acc = ak.GetModuleAccount(suite.ctx, auctiontypes.ModuleName)
|
||||
// should be this exact value because...?
|
||||
suite.Equal(int64(71955653865), bk.GetBalance(suite.ctx, acc.GetAddress(), "debt").Amount.Int64())
|
||||
}
|
||||
|
||||
func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
||||
// test setup
|
||||
// starting with zero cdps, add a single cdp of
|
||||
// xrp backed 1:1 with usdx
|
||||
err := suite.keeper.AddCdp(suite.ctx, suite.addrs[0], c("xrp", 10000000000), c("usdx", 1000000000), "xrp-a")
|
||||
suite.NoError(err)
|
||||
// verify the total value of all assets in cdps composed of xrp-a/usdx pair equals the amount of the single cdp we just added above
|
||||
suite.Equal(i(1000000000), suite.keeper.GetTotalPrincipal(suite.ctx, "xrp-a", "usdx"))
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
bk := suite.app.GetBankKeeper()
|
||||
@ -174,6 +221,73 @@ func (suite *ModuleTestSuite) TestSeizeSingleCdpWithFees() {
|
||||
suite.False(found)
|
||||
}
|
||||
|
||||
func (suite *ModuleTestSuite) TestCDPBeginBlockerRunsOnlyOnConfiguredInterval() {
|
||||
// test setup, creating
|
||||
// 50 xrp cdps each with
|
||||
// collateral: 10000000000
|
||||
// debt: between 750000000 - 1249000000
|
||||
// if debt above 10000000000,
|
||||
// cdp added to tracker / liquidation list
|
||||
// debt total added to trackers debt total
|
||||
// 50 btc cdps each with
|
||||
// collateral: 10000000000
|
||||
// debt: between 2700000000 - 5332000000
|
||||
// if debt above 4000000000,
|
||||
// cdp added to tracker / liquidation list
|
||||
// debt total added to trackers debt total
|
||||
|
||||
// naively we expect roughly half of the cdps to be above the debt tracking floor, roughly 25 of them collaterallized with xrp, the other 25 with btcb
|
||||
|
||||
// usdx is the principal for all cdps
|
||||
suite.createCdps()
|
||||
ak := suite.app.GetAccountKeeper()
|
||||
bk := suite.app.GetBankKeeper()
|
||||
|
||||
// set the cdp begin blocker to run every other block
|
||||
params := suite.keeper.GetParams(suite.ctx)
|
||||
params.LiquidationBlockInterval = 2
|
||||
suite.keeper.SetParams(suite.ctx, params)
|
||||
|
||||
// test case 1 setup
|
||||
acc := ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
// track how much xrp collateral exists in the cdp module
|
||||
originalXrpCollateral := bk.GetBalance(suite.ctx, acc.GetAddress(), "xrp").Amount
|
||||
// set the trading price for xrp:usd pools
|
||||
suite.setPrice(d("0.2"), "xrp:usd")
|
||||
|
||||
// test case 1 execution
|
||||
cdp.BeginBlocker(suite.ctx, abci.RequestBeginBlock{Header: suite.ctx.BlockHeader()}, suite.keeper)
|
||||
|
||||
// test case 1 assert
|
||||
acc = ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
// get the current amount of xrp held by the cdp module
|
||||
finalXrpCollateral := bk.GetBalance(suite.ctx, acc.GetAddress(), "xrp").Amount
|
||||
seizedXrpCollateral := originalXrpCollateral.Sub(finalXrpCollateral)
|
||||
// calculate the number of cdps that were liquidated based on the total
|
||||
// seized collateral divided by the size of each cdp when it was created
|
||||
xrpLiquidations := int(seizedXrpCollateral.Quo(i(10000000000)).Int64())
|
||||
// should be 0 because the cdp begin blocker is configured to
|
||||
// skip execution every odd numbered block
|
||||
suite.Equal(0, xrpLiquidations, "expected cdp begin blocker not to run liqudations")
|
||||
|
||||
// test case 2 setup
|
||||
// simulate running the second block of the chain
|
||||
suite.ctx = suite.ctx.WithBlockHeight(2)
|
||||
|
||||
// test case 2 execution
|
||||
cdp.BeginBlocker(suite.ctx, abci.RequestBeginBlock{Header: suite.ctx.BlockHeader()}, suite.keeper)
|
||||
|
||||
// test case 2 assert
|
||||
acc = ak.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
// get the current amount of xrp held by the cdp module
|
||||
finalXrpCollateral = bk.GetBalance(suite.ctx, acc.GetAddress(), "xrp").Amount
|
||||
seizedXrpCollateral = originalXrpCollateral.Sub(finalXrpCollateral)
|
||||
// calculate the number of cdps that were liquidated based on the total
|
||||
// seized collateral divided by the size of each cdp when it was created
|
||||
xrpLiquidations = int(seizedXrpCollateral.Quo(i(10000000000)).Int64())
|
||||
suite.Greater(xrpLiquidations, 0, "expected cdp begin blocker to run liquidations")
|
||||
}
|
||||
|
||||
func TestModuleTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(ModuleTestSuite))
|
||||
}
|
||||
|
@ -210,6 +210,7 @@ func (suite *GenesisTestSuite) Test_InitExportGenesis() {
|
||||
SurplusAuctionLot: types.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: types.DefaultDebtThreshold,
|
||||
DebtAuctionLot: types.DefaultDebtLot,
|
||||
LiquidationBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
|
@ -118,6 +118,7 @@ func NewCDPGenStateMulti(cdc codec.JSONCodec) app.GenesisState {
|
||||
SurplusAuctionLot: types.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: types.DefaultDebtThreshold,
|
||||
DebtAuctionLot: types.DefaultDebtLot,
|
||||
LiquidationBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
|
@ -47,6 +47,7 @@ func NewCDPGenState(cdc codec.JSONCodec, asset string, liquidationRatio sdk.Dec)
|
||||
SurplusAuctionLot: types.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: types.DefaultDebtThreshold,
|
||||
DebtAuctionLot: types.DefaultDebtLot,
|
||||
LiquidationBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: asset,
|
||||
@ -160,6 +161,7 @@ func NewCDPGenStateMulti(cdc codec.JSONCodec) app.GenesisState {
|
||||
SurplusAuctionLot: types.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: types.DefaultDebtThreshold,
|
||||
DebtAuctionLot: types.DefaultDebtLot,
|
||||
LiquidationBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
@ -253,6 +255,7 @@ func NewCDPGenStateHighDebtLimit(cdc codec.JSONCodec) app.GenesisState {
|
||||
SurplusAuctionLot: types.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: types.DefaultDebtThreshold,
|
||||
DebtAuctionLot: types.DefaultDebtLot,
|
||||
LiquidationBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: types.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
|
23
x/cdp/keeper/migrations.go
Normal file
23
x/cdp/keeper/migrations.go
Normal file
@ -0,0 +1,23 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
v2 "github.com/kava-labs/kava/x/cdp/migrations/v2"
|
||||
)
|
||||
|
||||
// Migrator is a struct for handling in-place store migrations.
|
||||
type Migrator struct {
|
||||
keeper Keeper
|
||||
}
|
||||
|
||||
// NewMigrator returns a new Migrator.
|
||||
func NewMigrator(keeper Keeper) Migrator {
|
||||
return Migrator{
|
||||
keeper: keeper,
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate1to2 migrates from version 1 to 2.
|
||||
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
|
||||
return v2.MigrateStore(ctx, m.keeper.paramSubspace)
|
||||
}
|
@ -12,7 +12,7 @@ import (
|
||||
// GetParams returns the params from the store
|
||||
func (k Keeper) GetParams(ctx sdk.Context) types.Params {
|
||||
var p types.Params
|
||||
k.paramSubspace.GetParamSet(ctx, &p)
|
||||
k.paramSubspace.GetParamSetIfExists(ctx, &p)
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -1,109 +0,0 @@
|
||||
package v0_15
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// ModuleName The name that will be used throughout the module
|
||||
ModuleName = "cdp"
|
||||
)
|
||||
|
||||
// GenesisState is the state that must be provided at genesis.
|
||||
type GenesisState struct {
|
||||
Params Params `json:"params" yaml:"params"`
|
||||
CDPs CDPs `json:"cdps" yaml:"cdps"`
|
||||
Deposits Deposits `json:"deposits" yaml:"deposits"`
|
||||
StartingCdpID uint64 `json:"starting_cdp_id" yaml:"starting_cdp_id"`
|
||||
DebtDenom string `json:"debt_denom" yaml:"debt_denom"`
|
||||
GovDenom string `json:"gov_denom" yaml:"gov_denom"`
|
||||
PreviousAccumulationTimes GenesisAccumulationTimes `json:"previous_accumulation_times" yaml:"previous_accumulation_times"`
|
||||
TotalPrincipals GenesisTotalPrincipals `json:"total_principals" yaml:"total_principals"`
|
||||
}
|
||||
|
||||
// Params governance parameters for cdp module
|
||||
type Params struct {
|
||||
CollateralParams CollateralParams `json:"collateral_params" yaml:"collateral_params"`
|
||||
DebtParam DebtParam `json:"debt_param" yaml:"debt_param"`
|
||||
GlobalDebtLimit sdk.Coin `json:"global_debt_limit" yaml:"global_debt_limit"`
|
||||
SurplusAuctionThreshold sdkmath.Int `json:"surplus_auction_threshold" yaml:"surplus_auction_threshold"`
|
||||
SurplusAuctionLot sdkmath.Int `json:"surplus_auction_lot" yaml:"surplus_auction_lot"`
|
||||
DebtAuctionThreshold sdkmath.Int `json:"debt_auction_threshold" yaml:"debt_auction_threshold"`
|
||||
DebtAuctionLot sdkmath.Int `json:"debt_auction_lot" yaml:"debt_auction_lot"`
|
||||
CircuitBreaker bool `json:"circuit_breaker" yaml:"circuit_breaker"`
|
||||
}
|
||||
|
||||
// CollateralParams array of CollateralParam
|
||||
type CollateralParams []CollateralParam
|
||||
|
||||
// CollateralParam governance parameters for each collateral type within the cdp module
|
||||
type CollateralParam struct {
|
||||
Denom string `json:"denom" yaml:"denom"` // Coin name of collateral type
|
||||
Type string `json:"type" yaml:"type"`
|
||||
LiquidationRatio sdk.Dec `json:"liquidation_ratio" yaml:"liquidation_ratio"` // The ratio (Collateral (priced in stable coin) / Debt) under which a CDP will be liquidated
|
||||
DebtLimit sdk.Coin `json:"debt_limit" yaml:"debt_limit"` // Maximum amount of debt allowed to be drawn from this collateral type
|
||||
StabilityFee sdk.Dec `json:"stability_fee" yaml:"stability_fee"` // per second stability fee for loans opened using this collateral
|
||||
AuctionSize sdkmath.Int `json:"auction_size" yaml:"auction_size"` // Max amount of collateral to sell off in any one auction.
|
||||
LiquidationPenalty sdk.Dec `json:"liquidation_penalty" yaml:"liquidation_penalty"` // percentage penalty (between [0, 1]) applied to a cdp if it is liquidated
|
||||
Prefix byte `json:"prefix" yaml:"prefix"`
|
||||
SpotMarketID string `json:"spot_market_id" yaml:"spot_market_id"` // marketID of the spot price of the asset from the pricefeed - used for opening CDPs, depositing, withdrawing
|
||||
LiquidationMarketID string `json:"liquidation_market_id" yaml:"liquidation_market_id"` // marketID of the pricefeed used for liquidation
|
||||
KeeperRewardPercentage sdk.Dec `json:"keeper_reward_percentage" yaml:"keeper_reward_percentage"` // the percentage of a CDPs collateral that gets rewarded to a keeper that liquidates the position
|
||||
CheckCollateralizationIndexCount sdkmath.Int `json:"check_collateralization_index_count" yaml:"check_collateralization_index_count"` // the number of cdps that will be checked for liquidation in the begin blocker
|
||||
ConversionFactor sdkmath.Int `json:"conversion_factor" yaml:"conversion_factor"` // factor for converting internal units to one base unit of collateral
|
||||
}
|
||||
|
||||
// CDPs a collection of CDP objects
|
||||
type CDPs []CDP
|
||||
|
||||
// CDP is the state of a single collateralized debt position.
|
||||
type CDP struct {
|
||||
ID uint64 `json:"id" yaml:"id"` // unique id for cdp
|
||||
Owner sdk.AccAddress `json:"owner" yaml:"owner"` // Account that authorizes changes to the CDP
|
||||
Type string `json:"type" yaml:"type"` // string representing the unique collateral type of the CDP
|
||||
Collateral sdk.Coin `json:"collateral" yaml:"collateral"` // Amount of collateral stored in this CDP
|
||||
Principal sdk.Coin `json:"principal" yaml:"principal"` // Amount of debt drawn using the CDP
|
||||
AccumulatedFees sdk.Coin `json:"accumulated_fees" yaml:"accumulated_fees"` // Fees accumulated since the CDP was opened or debt was last repaid
|
||||
FeesUpdated time.Time `json:"fees_updated" yaml:"fees_updated"` // The time when fees were last updated
|
||||
InterestFactor sdk.Dec `json:"interest_factor" yaml:"interest_factor"` // the interest factor when fees were last calculated for this CDP
|
||||
}
|
||||
|
||||
// Deposits a collection of Deposit objects
|
||||
type Deposits []Deposit
|
||||
|
||||
// Deposit defines an amount of coins deposited by an account to a cdp
|
||||
type Deposit struct {
|
||||
CdpID uint64 `json:"cdp_id" yaml:"cdp_id"` // cdpID of the cdp
|
||||
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"` // Address of the depositor
|
||||
Amount sdk.Coin `json:"amount" yaml:"amount"` // Deposit amount
|
||||
}
|
||||
|
||||
// GenesisAccumulationTimes slice of GenesisAccumulationTime
|
||||
type GenesisAccumulationTimes []GenesisAccumulationTime
|
||||
|
||||
// GenesisAccumulationTime stores the previous distribution time and its corresponding denom
|
||||
type GenesisAccumulationTime struct {
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
PreviousAccumulationTime time.Time `json:"previous_accumulation_time" yaml:"previous_accumulation_time"`
|
||||
InterestFactor sdk.Dec `json:"interest_factor" yaml:"interest_factor"`
|
||||
}
|
||||
|
||||
// GenesisTotalPrincipals slice of GenesisTotalPrincipal
|
||||
type GenesisTotalPrincipals []GenesisTotalPrincipal
|
||||
|
||||
// GenesisTotalPrincipal stores the total principal and its corresponding collateral type
|
||||
type GenesisTotalPrincipal struct {
|
||||
CollateralType string `json:"collateral_type" yaml:"collateral_type"`
|
||||
TotalPrincipal sdkmath.Int `json:"total_principal" yaml:"total_principal"`
|
||||
}
|
||||
|
||||
// DebtParam governance params for debt assets
|
||||
type DebtParam struct {
|
||||
Denom string `json:"denom" yaml:"denom"`
|
||||
ReferenceAsset string `json:"reference_asset" yaml:"reference_asset"`
|
||||
ConversionFactor sdkmath.Int `json:"conversion_factor" yaml:"conversion_factor"`
|
||||
DebtFloor sdkmath.Int `json:"debt_floor" yaml:"debt_floor"` // minimum active loan size, used to prevent dust
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
package v0_16
|
||||
|
||||
import (
|
||||
v015cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_15"
|
||||
v016cdp "github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
func migrateParams(params v015cdp.Params) v016cdp.Params {
|
||||
// migrate collateral params
|
||||
collateralParams := make(v016cdp.CollateralParams, len(params.CollateralParams))
|
||||
for i, cp := range params.CollateralParams {
|
||||
collateralParams[i] = v016cdp.CollateralParam{
|
||||
Denom: cp.Denom,
|
||||
Type: cp.Type,
|
||||
LiquidationRatio: cp.LiquidationRatio,
|
||||
DebtLimit: cp.DebtLimit,
|
||||
StabilityFee: cp.StabilityFee,
|
||||
AuctionSize: cp.AuctionSize,
|
||||
LiquidationPenalty: cp.LiquidationPenalty,
|
||||
SpotMarketID: cp.SpotMarketID,
|
||||
LiquidationMarketID: cp.LiquidationMarketID,
|
||||
KeeperRewardPercentage: cp.KeeperRewardPercentage,
|
||||
CheckCollateralizationIndexCount: cp.CheckCollateralizationIndexCount,
|
||||
ConversionFactor: cp.ConversionFactor,
|
||||
}
|
||||
}
|
||||
|
||||
return v016cdp.Params{
|
||||
CollateralParams: collateralParams,
|
||||
DebtParam: v016cdp.DebtParam{
|
||||
Denom: params.DebtParam.Denom,
|
||||
ReferenceAsset: params.DebtParam.ReferenceAsset,
|
||||
ConversionFactor: params.DebtParam.ConversionFactor,
|
||||
DebtFloor: params.DebtParam.DebtFloor,
|
||||
},
|
||||
GlobalDebtLimit: params.GlobalDebtLimit,
|
||||
SurplusAuctionThreshold: params.SurplusAuctionThreshold,
|
||||
SurplusAuctionLot: params.SurplusAuctionLot,
|
||||
DebtAuctionThreshold: params.DebtAuctionThreshold,
|
||||
DebtAuctionLot: params.DebtAuctionLot,
|
||||
CircuitBreaker: params.CircuitBreaker,
|
||||
}
|
||||
}
|
||||
|
||||
func migrateCDPs(oldCDPs v015cdp.CDPs) v016cdp.CDPs {
|
||||
cdps := make(v016cdp.CDPs, len(oldCDPs))
|
||||
for i, cdp := range oldCDPs {
|
||||
cdps[i] = v016cdp.CDP{
|
||||
ID: cdp.ID,
|
||||
Owner: cdp.Owner,
|
||||
Type: cdp.Type,
|
||||
Collateral: cdp.Collateral,
|
||||
Principal: cdp.Principal,
|
||||
AccumulatedFees: cdp.AccumulatedFees,
|
||||
FeesUpdated: cdp.FeesUpdated,
|
||||
InterestFactor: cdp.InterestFactor,
|
||||
}
|
||||
}
|
||||
return cdps
|
||||
}
|
||||
|
||||
func migrateDeposits(oldDeposits v015cdp.Deposits) v016cdp.Deposits {
|
||||
deposits := make(v016cdp.Deposits, len(oldDeposits))
|
||||
for i, deposit := range oldDeposits {
|
||||
deposits[i] = v016cdp.Deposit{
|
||||
CdpID: deposit.CdpID,
|
||||
Depositor: deposit.Depositor,
|
||||
Amount: deposit.Amount,
|
||||
}
|
||||
}
|
||||
return deposits
|
||||
}
|
||||
|
||||
func migratePrevAccTimes(oldPrevAccTimes v015cdp.GenesisAccumulationTimes) v016cdp.GenesisAccumulationTimes {
|
||||
prevAccTimes := make(v016cdp.GenesisAccumulationTimes, len(oldPrevAccTimes))
|
||||
for i, prevAccTime := range oldPrevAccTimes {
|
||||
prevAccTimes[i] = v016cdp.GenesisAccumulationTime{
|
||||
CollateralType: prevAccTime.CollateralType,
|
||||
PreviousAccumulationTime: prevAccTime.PreviousAccumulationTime,
|
||||
InterestFactor: prevAccTime.InterestFactor,
|
||||
}
|
||||
}
|
||||
return prevAccTimes
|
||||
}
|
||||
|
||||
func migrateTotalPrincipals(oldTotalPrincipals v015cdp.GenesisTotalPrincipals) v016cdp.GenesisTotalPrincipals {
|
||||
totalPrincipals := make(v016cdp.GenesisTotalPrincipals, len(oldTotalPrincipals))
|
||||
for i, tp := range oldTotalPrincipals {
|
||||
totalPrincipals[i] = v016cdp.GenesisTotalPrincipal{
|
||||
CollateralType: tp.CollateralType,
|
||||
TotalPrincipal: tp.TotalPrincipal,
|
||||
}
|
||||
}
|
||||
return totalPrincipals
|
||||
}
|
||||
|
||||
// Migrate converts v0.15 cdp state and returns it in v0.16 format
|
||||
func Migrate(oldState v015cdp.GenesisState) *v016cdp.GenesisState {
|
||||
return &v016cdp.GenesisState{
|
||||
Params: migrateParams(oldState.Params),
|
||||
CDPs: migrateCDPs(oldState.CDPs),
|
||||
Deposits: migrateDeposits(oldState.Deposits),
|
||||
StartingCdpID: oldState.StartingCdpID,
|
||||
DebtDenom: oldState.DebtDenom,
|
||||
GovDenom: oldState.GovDenom,
|
||||
PreviousAccumulationTimes: migratePrevAccTimes(oldState.PreviousAccumulationTimes),
|
||||
TotalPrincipals: migrateTotalPrincipals(oldState.TotalPrincipals),
|
||||
}
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
package v0_16
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
app "github.com/kava-labs/kava/app"
|
||||
v015cdp "github.com/kava-labs/kava/x/cdp/legacy/v0_15"
|
||||
v016cdp "github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
type migrateTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
addresses []sdk.AccAddress
|
||||
v15genstate v015cdp.GenesisState
|
||||
cdc codec.Codec
|
||||
legacyCdc *codec.LegacyAmino
|
||||
}
|
||||
|
||||
func (s *migrateTestSuite) SetupTest() {
|
||||
app.SetSDKConfig()
|
||||
|
||||
s.v15genstate = v015cdp.GenesisState{
|
||||
Params: v015cdp.Params{},
|
||||
CDPs: v015cdp.CDPs{},
|
||||
Deposits: v015cdp.Deposits{},
|
||||
StartingCdpID: 1,
|
||||
DebtDenom: "usdx",
|
||||
GovDenom: "ukava",
|
||||
PreviousAccumulationTimes: v015cdp.GenesisAccumulationTimes{},
|
||||
TotalPrincipals: v015cdp.GenesisTotalPrincipals{},
|
||||
}
|
||||
|
||||
config := app.MakeEncodingConfig()
|
||||
s.cdc = config.Marshaler
|
||||
|
||||
legacyCodec := codec.NewLegacyAmino()
|
||||
s.legacyCdc = legacyCodec
|
||||
|
||||
_, accAddresses := app.GeneratePrivKeyAddressPairs(10)
|
||||
s.addresses = accAddresses
|
||||
}
|
||||
|
||||
func (s *migrateTestSuite) TestMigrate_JSON() {
|
||||
file := filepath.Join("testdata", "v15-cdp.json")
|
||||
data, err := ioutil.ReadFile(file)
|
||||
s.Require().NoError(err)
|
||||
err = s.legacyCdc.UnmarshalJSON(data, &s.v15genstate)
|
||||
s.Require().NoError(err)
|
||||
genstate := Migrate(s.v15genstate)
|
||||
actual := s.cdc.MustMarshalJSON(genstate)
|
||||
|
||||
file = filepath.Join("testdata", "v16-cdp.json")
|
||||
expected, err := ioutil.ReadFile(file)
|
||||
s.Require().NoError(err)
|
||||
s.Require().JSONEq(string(expected), string(actual))
|
||||
}
|
||||
|
||||
func (s *migrateTestSuite) TestMigrate_GenState() {
|
||||
s.v15genstate = v015cdp.GenesisState{
|
||||
StartingCdpID: 2,
|
||||
DebtDenom: "usdx",
|
||||
GovDenom: "ukava",
|
||||
Params: v015cdp.Params{
|
||||
CollateralParams: v015cdp.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.012"),
|
||||
LiquidationPenalty: sdk.MustNewDecFromStr("0.05"),
|
||||
AuctionSize: sdkmath.NewInt(70),
|
||||
SpotMarketID: "xrp:usd",
|
||||
LiquidationMarketID: "xrp:usd",
|
||||
KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"),
|
||||
CheckCollateralizationIndexCount: sdkmath.NewInt(10),
|
||||
ConversionFactor: sdkmath.NewInt(6),
|
||||
},
|
||||
},
|
||||
DebtParam: v015cdp.DebtParam{
|
||||
Denom: "usdx",
|
||||
ReferenceAsset: "usd",
|
||||
ConversionFactor: sdkmath.NewInt(6),
|
||||
DebtFloor: sdkmath.NewInt(100),
|
||||
},
|
||||
GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
SurplusAuctionThreshold: sdkmath.NewInt(6),
|
||||
SurplusAuctionLot: sdkmath.NewInt(7),
|
||||
DebtAuctionThreshold: sdkmath.NewInt(8),
|
||||
DebtAuctionLot: sdkmath.NewInt(9),
|
||||
},
|
||||
CDPs: v015cdp.CDPs{
|
||||
{
|
||||
ID: 2,
|
||||
Owner: s.addresses[0],
|
||||
Type: "xrp-a",
|
||||
Collateral: sdk.NewCoin("xrp", sdkmath.NewInt(2123)),
|
||||
Principal: sdk.NewCoin("usdx", sdkmath.NewInt(100)),
|
||||
AccumulatedFees: sdk.NewCoin("usdx", sdk.ZeroInt()),
|
||||
FeesUpdated: time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
InterestFactor: sdk.NewDec(1),
|
||||
},
|
||||
},
|
||||
Deposits: v015cdp.Deposits{
|
||||
{
|
||||
CdpID: 1,
|
||||
Depositor: s.addresses[0],
|
||||
Amount: sdk.NewCoin("usdx", sdkmath.NewInt(100)),
|
||||
},
|
||||
{
|
||||
CdpID: 2,
|
||||
Depositor: s.addresses[1],
|
||||
Amount: sdk.NewCoin("ukava", sdkmath.NewInt(1200)),
|
||||
},
|
||||
},
|
||||
PreviousAccumulationTimes: v015cdp.GenesisAccumulationTimes{
|
||||
{
|
||||
CollateralType: "usdx",
|
||||
PreviousAccumulationTime: time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
InterestFactor: sdk.MustNewDecFromStr("0.02"),
|
||||
},
|
||||
},
|
||||
TotalPrincipals: v015cdp.GenesisTotalPrincipals{
|
||||
{
|
||||
CollateralType: "usdx",
|
||||
TotalPrincipal: sdkmath.NewInt(1200),
|
||||
},
|
||||
},
|
||||
}
|
||||
expected := v016cdp.GenesisState{
|
||||
StartingCdpID: 2,
|
||||
DebtDenom: "usdx",
|
||||
GovDenom: "ukava",
|
||||
Params: v016cdp.Params{
|
||||
CollateralParams: v016cdp.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
Type: "xrp-a",
|
||||
LiquidationRatio: sdk.MustNewDecFromStr("2.0"),
|
||||
DebtLimit: sdk.NewInt64Coin("usdx", 500000000000),
|
||||
StabilityFee: sdk.MustNewDecFromStr("1.012"),
|
||||
LiquidationPenalty: sdk.MustNewDecFromStr("0.05"),
|
||||
AuctionSize: sdkmath.NewInt(70),
|
||||
SpotMarketID: "xrp:usd",
|
||||
LiquidationMarketID: "xrp:usd",
|
||||
KeeperRewardPercentage: sdk.MustNewDecFromStr("0.01"),
|
||||
CheckCollateralizationIndexCount: sdkmath.NewInt(10),
|
||||
ConversionFactor: sdkmath.NewInt(6),
|
||||
},
|
||||
},
|
||||
DebtParam: v016cdp.DebtParam{
|
||||
Denom: "usdx",
|
||||
ReferenceAsset: "usd",
|
||||
ConversionFactor: sdkmath.NewInt(6),
|
||||
DebtFloor: sdkmath.NewInt(100),
|
||||
},
|
||||
GlobalDebtLimit: sdk.NewInt64Coin("usdx", 1000000000000),
|
||||
SurplusAuctionThreshold: sdkmath.NewInt(6),
|
||||
SurplusAuctionLot: sdkmath.NewInt(7),
|
||||
DebtAuctionThreshold: sdkmath.NewInt(8),
|
||||
DebtAuctionLot: sdkmath.NewInt(9),
|
||||
},
|
||||
CDPs: v016cdp.CDPs{
|
||||
{
|
||||
ID: 2,
|
||||
Owner: s.addresses[0],
|
||||
Type: "xrp-a",
|
||||
Collateral: sdk.NewCoin("xrp", sdkmath.NewInt(2123)),
|
||||
Principal: sdk.NewCoin("usdx", sdkmath.NewInt(100)),
|
||||
AccumulatedFees: sdk.NewCoin("usdx", sdk.ZeroInt()),
|
||||
FeesUpdated: time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
InterestFactor: sdk.NewDec(1),
|
||||
},
|
||||
},
|
||||
Deposits: v016cdp.Deposits{
|
||||
{
|
||||
CdpID: 1,
|
||||
Depositor: s.addresses[0],
|
||||
Amount: sdk.NewCoin("usdx", sdkmath.NewInt(100)),
|
||||
},
|
||||
{
|
||||
CdpID: 2,
|
||||
Depositor: s.addresses[1],
|
||||
Amount: sdk.NewCoin("ukava", sdkmath.NewInt(1200)),
|
||||
},
|
||||
},
|
||||
PreviousAccumulationTimes: v016cdp.GenesisAccumulationTimes{
|
||||
{
|
||||
CollateralType: "usdx",
|
||||
PreviousAccumulationTime: time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
InterestFactor: sdk.MustNewDecFromStr("0.02"),
|
||||
},
|
||||
},
|
||||
TotalPrincipals: v016cdp.GenesisTotalPrincipals{
|
||||
{
|
||||
CollateralType: "usdx",
|
||||
TotalPrincipal: sdkmath.NewInt(1200),
|
||||
},
|
||||
},
|
||||
}
|
||||
genState := Migrate(s.v15genstate)
|
||||
s.Require().Equal(expected, *genState)
|
||||
}
|
||||
|
||||
func TestCdpMigrateTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(migrateTestSuite))
|
||||
}
|
135
x/cdp/legacy/v0_16/testdata/v15-cdp.json
vendored
135
x/cdp/legacy/v0_16/testdata/v15-cdp.json
vendored
@ -1,135 +0,0 @@
|
||||
{
|
||||
"cdps": [
|
||||
{
|
||||
"accumulated_fees": {
|
||||
"amount": "36088",
|
||||
"denom": "usdx"
|
||||
},
|
||||
"collateral": {
|
||||
"amount": "40911876",
|
||||
"denom": "bnb"
|
||||
},
|
||||
"fees_updated": "2021-11-05T21:13:12.85608847Z",
|
||||
"id": "19",
|
||||
"interest_factor": "1.002881426571765716",
|
||||
"owner": "kava1u4p6a2yse66ewfndw4j7ppsa777vdcex3m4n9s",
|
||||
"principal": {
|
||||
"amount": "10016831",
|
||||
"denom": "usdx"
|
||||
},
|
||||
"type": "bnb-a"
|
||||
},
|
||||
{
|
||||
"accumulated_fees": {
|
||||
"amount": "156662",
|
||||
"denom": "usdx"
|
||||
},
|
||||
"collateral": {
|
||||
"amount": "88268546",
|
||||
"denom": "bnb"
|
||||
},
|
||||
"fees_updated": "2021-11-05T21:13:12.85608847Z",
|
||||
"id": "22",
|
||||
"interest_factor": "1.002881426571765716",
|
||||
"owner": "kava1e8xjfylam4nvugcmkxwvuxh22uvvad5vknu4yh",
|
||||
"principal": {
|
||||
"amount": "10000000",
|
||||
"denom": "usdx"
|
||||
},
|
||||
"type": "bnb-a"
|
||||
}
|
||||
],
|
||||
"debt_denom": "debt",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": {
|
||||
"amount": "40911876",
|
||||
"denom": "bnb"
|
||||
},
|
||||
"cdp_id": "19",
|
||||
"depositor": "kava1u4p6a2yse66ewfndw4j7ppsa777vdcex3m4n9s"
|
||||
},
|
||||
{
|
||||
"amount": {
|
||||
"amount": "88268546",
|
||||
"denom": "bnb"
|
||||
},
|
||||
"cdp_id": "22",
|
||||
"depositor": "kava1e8xjfylam4nvugcmkxwvuxh22uvvad5vknu4yh"
|
||||
}
|
||||
],
|
||||
"gov_denom": "ukava",
|
||||
"params": {
|
||||
"circuit_breaker": false,
|
||||
"collateral_params": [
|
||||
{
|
||||
"auction_size": "50000000000",
|
||||
"conversion_factor": "8",
|
||||
"debt_limit": {
|
||||
"amount": "20000000000000",
|
||||
"denom": "usdx"
|
||||
},
|
||||
"denom": "bnb",
|
||||
"liquidation_market_id": "bnb:usd:30",
|
||||
"liquidation_penalty": "0.050000000000000000",
|
||||
"liquidation_ratio": "1.500000000000000000",
|
||||
"keeper_reward_percentage": "0.01",
|
||||
"check_collateralization_index_count": "10",
|
||||
"prefix": 1,
|
||||
"spot_market_id": "bnb:usd",
|
||||
"stability_fee": "1.000000000782997700",
|
||||
"type": "bnb-a"
|
||||
},
|
||||
{
|
||||
"denom": "hbtc",
|
||||
"type": "hbtc-a",
|
||||
"liquidation_ratio": "1.500000000000000000",
|
||||
"debt_limit": {
|
||||
"denom": "usdx",
|
||||
"amount": "10000000000000"
|
||||
},
|
||||
"stability_fee": "1.000000001547125958",
|
||||
"auction_size": "1000000000000",
|
||||
"liquidation_penalty": "0.075000000000000000",
|
||||
"check_collateralization_index_count": "10",
|
||||
"keeper_reward_percentage": "0.01",
|
||||
"prefix": 8,
|
||||
"spot_market_id": "btc:usd",
|
||||
"liquidation_market_id": "btc:usd:30",
|
||||
"conversion_factor": "8"
|
||||
}
|
||||
],
|
||||
"debt_auction_lot": "10000000000",
|
||||
"debt_auction_threshold": "100000000000",
|
||||
"debt_param": {
|
||||
"conversion_factor": "6",
|
||||
"debt_floor": "10000000",
|
||||
"denom": "usdx",
|
||||
"reference_asset": "usd",
|
||||
"savings_rate": "0.950000000000000000"
|
||||
},
|
||||
"global_debt_limit": {
|
||||
"amount": "43000000000000",
|
||||
"denom": "usdx"
|
||||
},
|
||||
"savings_distribution_frequency": "43200000000000",
|
||||
"surplus_auction_lot": "10000000000",
|
||||
"surplus_auction_threshold": "500000000000"
|
||||
},
|
||||
"previous_distribution_time": "1970-01-01T00:00:00Z",
|
||||
"savings_rate_distributed": "0",
|
||||
"starting_cdp_id": "1",
|
||||
"previous_accumulation_times": [
|
||||
{
|
||||
"collateral_type": "bnb-a",
|
||||
"interest_factor": "1.002881426571765716",
|
||||
"previous_accumulation_time": "2021-11-05T21:13:12.85608847Z"
|
||||
}
|
||||
],
|
||||
"total_principals": [
|
||||
{
|
||||
"collateral_type": "bnb-a",
|
||||
"total_principal": "9285009581820"
|
||||
}
|
||||
]
|
||||
}
|
93
x/cdp/legacy/v0_16/testdata/v16-cdp.json
vendored
93
x/cdp/legacy/v0_16/testdata/v16-cdp.json
vendored
@ -1,93 +0,0 @@
|
||||
{
|
||||
"params": {
|
||||
"collateral_params": [
|
||||
{
|
||||
"denom": "bnb",
|
||||
"type": "bnb-a",
|
||||
"liquidation_ratio": "1.500000000000000000",
|
||||
"debt_limit": { "denom": "usdx", "amount": "20000000000000" },
|
||||
"stability_fee": "1.000000000782997700",
|
||||
"auction_size": "50000000000",
|
||||
"liquidation_penalty": "0.050000000000000000",
|
||||
"spot_market_id": "bnb:usd",
|
||||
"liquidation_market_id": "bnb:usd:30",
|
||||
"keeper_reward_percentage": "0.010000000000000000",
|
||||
"check_collateralization_index_count": "10",
|
||||
"conversion_factor": "8"
|
||||
},
|
||||
{
|
||||
"denom": "hbtc",
|
||||
"type": "hbtc-a",
|
||||
"liquidation_ratio": "1.500000000000000000",
|
||||
"debt_limit": { "denom": "usdx", "amount": "10000000000000" },
|
||||
"stability_fee": "1.000000001547125958",
|
||||
"auction_size": "1000000000000",
|
||||
"liquidation_penalty": "0.075000000000000000",
|
||||
"spot_market_id": "btc:usd",
|
||||
"liquidation_market_id": "btc:usd:30",
|
||||
"keeper_reward_percentage": "0.010000000000000000",
|
||||
"check_collateralization_index_count": "10",
|
||||
"conversion_factor": "8"
|
||||
}
|
||||
],
|
||||
"debt_param": {
|
||||
"denom": "usdx",
|
||||
"reference_asset": "usd",
|
||||
"conversion_factor": "6",
|
||||
"debt_floor": "10000000"
|
||||
},
|
||||
"global_debt_limit": { "denom": "usdx", "amount": "43000000000000" },
|
||||
"surplus_auction_threshold": "500000000000",
|
||||
"surplus_auction_lot": "10000000000",
|
||||
"debt_auction_threshold": "100000000000",
|
||||
"debt_auction_lot": "10000000000",
|
||||
"circuit_breaker": false
|
||||
},
|
||||
"cdps": [
|
||||
{
|
||||
"id": "19",
|
||||
"owner": "kava1u4p6a2yse66ewfndw4j7ppsa777vdcex3m4n9s",
|
||||
"type": "bnb-a",
|
||||
"collateral": { "denom": "bnb", "amount": "40911876" },
|
||||
"principal": { "denom": "usdx", "amount": "10016831" },
|
||||
"accumulated_fees": { "denom": "usdx", "amount": "36088" },
|
||||
"fees_updated": "2021-11-05T21:13:12.856088470Z",
|
||||
"interest_factor": "1.002881426571765716"
|
||||
},
|
||||
{
|
||||
"id": "22",
|
||||
"owner": "kava1e8xjfylam4nvugcmkxwvuxh22uvvad5vknu4yh",
|
||||
"type": "bnb-a",
|
||||
"collateral": { "denom": "bnb", "amount": "88268546" },
|
||||
"principal": { "denom": "usdx", "amount": "10000000" },
|
||||
"accumulated_fees": { "denom": "usdx", "amount": "156662" },
|
||||
"fees_updated": "2021-11-05T21:13:12.856088470Z",
|
||||
"interest_factor": "1.002881426571765716"
|
||||
}
|
||||
],
|
||||
"deposits": [
|
||||
{
|
||||
"cdp_id": "19",
|
||||
"depositor": "kava1u4p6a2yse66ewfndw4j7ppsa777vdcex3m4n9s",
|
||||
"amount": { "denom": "bnb", "amount": "40911876" }
|
||||
},
|
||||
{
|
||||
"cdp_id": "22",
|
||||
"depositor": "kava1e8xjfylam4nvugcmkxwvuxh22uvvad5vknu4yh",
|
||||
"amount": { "denom": "bnb", "amount": "88268546" }
|
||||
}
|
||||
],
|
||||
"starting_cdp_id": "1",
|
||||
"debt_denom": "debt",
|
||||
"gov_denom": "ukava",
|
||||
"previous_accumulation_times": [
|
||||
{
|
||||
"collateral_type": "bnb-a",
|
||||
"previous_accumulation_time": "2021-11-05T21:13:12.856088470Z",
|
||||
"interest_factor": "1.002881426571765716"
|
||||
}
|
||||
],
|
||||
"total_principals": [
|
||||
{ "collateral_type": "bnb-a", "total_principal": "9285009581820" }
|
||||
]
|
||||
}
|
22
x/cdp/migrations/v2/store.go
Normal file
22
x/cdp/migrations/v2/store.go
Normal file
@ -0,0 +1,22 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
"github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
// MigrateStore performs in-place store migrations for consensus version 2
|
||||
// V2 adds the begin_blocker_execution_block_interval param to parameters.
|
||||
func MigrateStore(ctx sdk.Context, paramstore paramtypes.Subspace) error {
|
||||
migrateParamsStore(ctx, paramstore)
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateParamsStore ensures the param key table exists and has the begin_blocker_execution_block_interval property
|
||||
func migrateParamsStore(ctx sdk.Context, paramstore paramtypes.Subspace) {
|
||||
if !paramstore.HasKeyTable() {
|
||||
paramstore.WithKeyTable(types.ParamKeyTable())
|
||||
}
|
||||
paramstore.Set(ctx, types.KeyBeginBlockerExecutionBlockInterval, types.DefaultBeginBlockerExecutionBlockInterval)
|
||||
}
|
63
x/cdp/migrations/v2/store_test.go
Normal file
63
x/cdp/migrations/v2/store_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package v2_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
|
||||
v2cdp "github.com/kava-labs/kava/x/cdp/migrations/v2"
|
||||
"github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
func TestStoreMigrationAddsKeyTableIncludingNewParam(t *testing.T) {
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
cdpKey := sdk.NewKVStoreKey(types.ModuleName)
|
||||
tcdpKey := sdk.NewTransientStoreKey("transient_test")
|
||||
ctx := testutil.DefaultContext(cdpKey, tcdpKey)
|
||||
paramstore := paramtypes.NewSubspace(encCfg.Codec, encCfg.Amino, cdpKey, tcdpKey, types.ModuleName)
|
||||
|
||||
// Check param doesn't exist before
|
||||
require.False(t, paramstore.Has(ctx, types.KeyBeginBlockerExecutionBlockInterval))
|
||||
|
||||
// Run migrations.
|
||||
err := v2cdp.MigrateStore(ctx, paramstore)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure the new params are set.
|
||||
require.True(t, paramstore.Has(ctx, types.KeyBeginBlockerExecutionBlockInterval))
|
||||
// Assert the value is what we expect
|
||||
result := types.DefaultBeginBlockerExecutionBlockInterval
|
||||
paramstore.Get(ctx, types.KeyBeginBlockerExecutionBlockInterval, &result)
|
||||
require.Equal(t, result, types.DefaultBeginBlockerExecutionBlockInterval)
|
||||
}
|
||||
|
||||
func TestStoreMigrationSetsNewParamOnExistingKeyTable(t *testing.T) {
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
cdpKey := sdk.NewKVStoreKey(types.ModuleName)
|
||||
tcdpKey := sdk.NewTransientStoreKey("transient_test")
|
||||
ctx := testutil.DefaultContext(cdpKey, tcdpKey)
|
||||
paramstore := paramtypes.NewSubspace(encCfg.Codec, encCfg.Amino, cdpKey, tcdpKey, types.ModuleName)
|
||||
paramstore.WithKeyTable(types.ParamKeyTable())
|
||||
|
||||
// expect it to have key table
|
||||
require.True(t, paramstore.HasKeyTable())
|
||||
// expect it to not have new param
|
||||
require.False(t, paramstore.Has(ctx, types.KeyBeginBlockerExecutionBlockInterval))
|
||||
|
||||
// Run migrations.
|
||||
err := v2cdp.MigrateStore(ctx, paramstore)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure the new params are set.
|
||||
require.True(t, paramstore.Has(ctx, types.KeyBeginBlockerExecutionBlockInterval))
|
||||
|
||||
// Assert the value is what we expect
|
||||
result := types.DefaultBeginBlockerExecutionBlockInterval
|
||||
paramstore.Get(ctx, types.KeyBeginBlockerExecutionBlockInterval, &result)
|
||||
require.Equal(t, result, types.DefaultBeginBlockerExecutionBlockInterval)
|
||||
}
|
@ -3,6 +3,7 @@ package cdp
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/spf13/cobra"
|
||||
@ -26,6 +27,9 @@ var (
|
||||
// _ module.AppModuleSimulation = AppModule{}
|
||||
)
|
||||
|
||||
// ConsensusVersion defines the current module consensus version.
|
||||
const ConsensusVersion = 2
|
||||
|
||||
// AppModuleBasic app module basics object
|
||||
type AppModuleBasic struct{}
|
||||
|
||||
@ -75,7 +79,7 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
|
||||
|
||||
// ConsensusVersion implements AppModule/ConsensusVersion.
|
||||
func (AppModule) ConsensusVersion() uint64 {
|
||||
return 1
|
||||
return ConsensusVersion
|
||||
}
|
||||
|
||||
// GetTxCmd returns the root tx command for the cdp module.
|
||||
@ -133,6 +137,11 @@ func (AppModule) QuerierRoute() string {
|
||||
func (am AppModule) RegisterServices(cfg module.Configurator) {
|
||||
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
|
||||
types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServerImpl(am.keeper))
|
||||
|
||||
m := keeper.NewMigrator(am.keeper)
|
||||
if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil {
|
||||
panic(fmt.Sprintf("failed to migrate x/cdp from version 1 to 2: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// InitGenesis module init-genesis
|
||||
|
@ -142,6 +142,7 @@ type Params struct {
|
||||
DebtAuctionThreshold github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=debt_auction_threshold,json=debtAuctionThreshold,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"debt_auction_threshold"`
|
||||
DebtAuctionLot github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=debt_auction_lot,json=debtAuctionLot,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"debt_auction_lot"`
|
||||
CircuitBreaker bool `protobuf:"varint,8,opt,name=circuit_breaker,json=circuitBreaker,proto3" json:"circuit_breaker,omitempty"`
|
||||
LiquidationBlockInterval int64 `protobuf:"varint,9,opt,name=liquidation_block_interval,json=liquidationBlockInterval,proto3" json:"liquidation_block_interval,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Params) Reset() { *m = Params{} }
|
||||
@ -205,6 +206,13 @@ func (m *Params) GetCircuitBreaker() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Params) GetLiquidationBlockInterval() int64 {
|
||||
if m != nil {
|
||||
return m.LiquidationBlockInterval
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// DebtParam defines governance params for debt assets
|
||||
type DebtParam struct {
|
||||
Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"`
|
||||
@ -456,81 +464,83 @@ func init() {
|
||||
func init() { proto.RegisterFile("kava/cdp/v1beta1/genesis.proto", fileDescriptor_e4494a90aaab0034) }
|
||||
|
||||
var fileDescriptor_e4494a90aaab0034 = []byte{
|
||||
// 1179 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6e, 0x1b, 0x37,
|
||||
0x10, 0xf6, 0x3a, 0x8a, 0x23, 0xd1, 0x8a, 0x24, 0x33, 0x4e, 0xb2, 0x76, 0x50, 0x49, 0x75, 0xd1,
|
||||
0xc6, 0x3d, 0x58, 0x42, 0x52, 0x20, 0x40, 0x81, 0xa2, 0xa9, 0x65, 0xc1, 0x81, 0x11, 0x17, 0x10,
|
||||
0xd6, 0x3e, 0xb5, 0x87, 0x05, 0x97, 0x4b, 0xc9, 0x84, 0x56, 0xcb, 0x2d, 0x49, 0xa9, 0xb6, 0x5f,
|
||||
0xa1, 0x28, 0x1a, 0xf4, 0x25, 0x0a, 0xe4, 0xdc, 0x87, 0x48, 0x6f, 0x41, 0x4f, 0x45, 0x0f, 0x72,
|
||||
0x21, 0xdf, 0xfb, 0x0c, 0x05, 0x7f, 0xf4, 0x63, 0xc9, 0x02, 0x02, 0x5b, 0xbd, 0x58, 0xcb, 0x19,
|
||||
0xce, 0xf7, 0xcd, 0x90, 0x33, 0xc3, 0x31, 0x28, 0xb6, 0x51, 0x0f, 0x55, 0x71, 0x98, 0x54, 0x7b,
|
||||
0xcf, 0x02, 0x22, 0xd1, 0xb3, 0x6a, 0x8b, 0xc4, 0x44, 0x50, 0x51, 0x49, 0x38, 0x93, 0x0c, 0x16,
|
||||
0x94, 0xbe, 0x82, 0xc3, 0xa4, 0x62, 0xf5, 0x9b, 0x45, 0xcc, 0x44, 0x87, 0x89, 0x6a, 0x80, 0x04,
|
||||
0x19, 0x19, 0x61, 0x46, 0x63, 0x63, 0xb1, 0xb9, 0x61, 0xf4, 0xbe, 0x5e, 0x55, 0xcd, 0xc2, 0xaa,
|
||||
0xd6, 0x5b, 0xac, 0xc5, 0x8c, 0x5c, 0x7d, 0x59, 0x69, 0xa9, 0xc5, 0x58, 0x2b, 0x22, 0x55, 0xbd,
|
||||
0x0a, 0xba, 0xcd, 0xaa, 0xa4, 0x1d, 0x22, 0x24, 0xea, 0x24, 0x76, 0xc3, 0xe6, 0x8c, 0x8f, 0xca,
|
||||
0x1f, 0xad, 0xdb, 0xfa, 0x23, 0x05, 0xb2, 0xaf, 0x8c, 0xc7, 0x47, 0x12, 0x49, 0x02, 0x5f, 0x80,
|
||||
0x95, 0x04, 0x71, 0xd4, 0x11, 0xae, 0x53, 0x76, 0xb6, 0x57, 0x9f, 0xbb, 0x95, 0xe9, 0x08, 0x2a,
|
||||
0x0d, 0xad, 0xaf, 0xa5, 0xde, 0xf5, 0x4b, 0x4b, 0x9e, 0xdd, 0x0d, 0x5f, 0x82, 0x14, 0x0e, 0x13,
|
||||
0xe1, 0x2e, 0x97, 0xef, 0x6c, 0xaf, 0x3e, 0x7f, 0x38, 0x6b, 0xb5, 0x57, 0x6f, 0xd4, 0xd6, 0x95,
|
||||
0xc9, 0xa0, 0x5f, 0x4a, 0xed, 0xd5, 0x1b, 0xe2, 0xed, 0x85, 0xf9, 0xf5, 0xb4, 0x21, 0x7c, 0x05,
|
||||
0xd2, 0x21, 0x49, 0x98, 0xa0, 0x52, 0xb8, 0x77, 0x34, 0xc8, 0xc6, 0x2c, 0x48, 0xdd, 0xec, 0xa8,
|
||||
0x15, 0x14, 0xd0, 0xdb, 0x8b, 0x52, 0xda, 0x0a, 0x84, 0x37, 0x32, 0x86, 0x5f, 0x82, 0xbc, 0x90,
|
||||
0x88, 0x4b, 0x1a, 0xb7, 0x7c, 0x1c, 0x26, 0x3e, 0x0d, 0xdd, 0x54, 0xd9, 0xd9, 0x4e, 0xd5, 0xd6,
|
||||
0x06, 0xfd, 0xd2, 0xfd, 0x23, 0xab, 0xda, 0x0b, 0x93, 0x83, 0xba, 0x77, 0x5f, 0x4c, 0x2c, 0x43,
|
||||
0xf8, 0x11, 0x00, 0x21, 0x09, 0xa4, 0x1f, 0x92, 0x98, 0x75, 0xdc, 0xbb, 0x65, 0x67, 0x3b, 0xe3,
|
||||
0x65, 0x94, 0xa4, 0xae, 0x04, 0xf0, 0x09, 0xc8, 0xb4, 0x58, 0xcf, 0x6a, 0x57, 0xb4, 0x36, 0xdd,
|
||||
0x62, 0x3d, 0xa3, 0xfc, 0xc9, 0x01, 0x4f, 0x12, 0x4e, 0x7a, 0x94, 0x75, 0x85, 0x8f, 0x30, 0xee,
|
||||
0x76, 0xba, 0x11, 0x92, 0x94, 0xc5, 0xbe, 0xbe, 0x0f, 0xf7, 0x9e, 0x8e, 0xe9, 0xf3, 0xd9, 0x98,
|
||||
0xec, 0xf1, 0xef, 0x4e, 0x98, 0x1c, 0xd3, 0x0e, 0xa9, 0x95, 0x6d, 0x8c, 0xee, 0x9c, 0x0d, 0xc2,
|
||||
0xdb, 0x18, 0xf2, 0xcd, 0xa8, 0x20, 0x07, 0x05, 0xc9, 0x24, 0x8a, 0xfc, 0x84, 0xd3, 0x18, 0xd3,
|
||||
0x04, 0x45, 0xc2, 0x4d, 0x6b, 0x0f, 0x9e, 0xce, 0xf5, 0xe0, 0x58, 0x19, 0x34, 0x86, 0xfb, 0x6b,
|
||||
0x45, 0xcb, 0xff, 0xe8, 0x5a, 0xb5, 0xf0, 0xf2, 0xf2, 0xaa, 0x60, 0xeb, 0xdf, 0xbb, 0x60, 0xc5,
|
||||
0xe4, 0x06, 0x3c, 0x01, 0x6b, 0x98, 0x45, 0x11, 0x92, 0x84, 0x2b, 0x1f, 0x86, 0x09, 0xa5, 0xf8,
|
||||
0x3f, 0xbe, 0x26, 0x35, 0x46, 0x5b, 0xb5, 0x79, 0xcd, 0xb5, 0xcc, 0x85, 0x29, 0x85, 0xf0, 0x0a,
|
||||
0x78, 0x4a, 0x02, 0xbf, 0xb1, 0x57, 0xa6, 0x39, 0xdc, 0x65, 0x9d, 0xb3, 0x4f, 0xae, 0x4b, 0x9c,
|
||||
0x40, 0x1a, 0x70, 0x93, 0xb6, 0xfa, 0x56, 0xb5, 0x00, 0xbe, 0x06, 0x6b, 0xad, 0x88, 0x05, 0x28,
|
||||
0xf2, 0x35, 0x50, 0x44, 0x3b, 0x54, 0xba, 0x77, 0x34, 0xd0, 0x46, 0xc5, 0xd6, 0x9f, 0x2a, 0xd6,
|
||||
0x09, 0x77, 0x69, 0x6c, 0x61, 0xf2, 0xc6, 0x52, 0xa1, 0x1f, 0x2a, 0x3b, 0x78, 0x0a, 0x36, 0x44,
|
||||
0x97, 0x27, 0x91, 0xca, 0x81, 0x2e, 0x36, 0xd7, 0x7f, 0xc2, 0x89, 0x38, 0x61, 0x91, 0x49, 0xc3,
|
||||
0x4c, 0xed, 0x2b, 0x65, 0xf9, 0x77, 0xbf, 0xf4, 0x59, 0x8b, 0xca, 0x93, 0x6e, 0x50, 0xc1, 0xac,
|
||||
0x63, 0xcb, 0xdc, 0xfe, 0xec, 0x88, 0xb0, 0x5d, 0x95, 0x67, 0x09, 0x11, 0x95, 0x83, 0x58, 0xfe,
|
||||
0xf9, 0xfb, 0x0e, 0xb0, 0x5e, 0x1c, 0xc4, 0xd2, 0x7b, 0x6c, 0xe1, 0x77, 0x0d, 0xfa, 0xf1, 0x10,
|
||||
0x1c, 0x46, 0xe0, 0xc1, 0x34, 0x73, 0xc4, 0xa4, 0x49, 0xe2, 0x5b, 0x72, 0xae, 0x5d, 0xe5, 0x3c,
|
||||
0x64, 0x12, 0x72, 0xf0, 0x48, 0x9f, 0xd6, 0x6c, 0x90, 0x2b, 0x0b, 0x20, 0x5c, 0x57, 0xd8, 0x33,
|
||||
0x11, 0x36, 0x41, 0xe1, 0x0a, 0xa7, 0x0a, 0xef, 0xde, 0x02, 0xd8, 0x72, 0x13, 0x6c, 0x2a, 0xb6,
|
||||
0xa7, 0x20, 0x8f, 0x29, 0xc7, 0x5d, 0x2a, 0xfd, 0x80, 0x13, 0xd4, 0x26, 0xdc, 0x4d, 0x97, 0x9d,
|
||||
0xed, 0xb4, 0x97, 0xb3, 0xe2, 0x9a, 0x91, 0x6e, 0xfd, 0xba, 0x0c, 0x32, 0xa3, 0xc4, 0x82, 0xeb,
|
||||
0xe0, 0xae, 0xe9, 0x0c, 0x8e, 0xee, 0x0c, 0x66, 0xa1, 0xc0, 0x38, 0x69, 0x12, 0x4e, 0x62, 0x4c,
|
||||
0x7c, 0x24, 0x04, 0x91, 0x3a, 0x49, 0x33, 0x5e, 0x6e, 0x24, 0xde, 0x55, 0x52, 0x48, 0x55, 0xc9,
|
||||
0xc4, 0x3d, 0xc2, 0x85, 0x8a, 0xad, 0x89, 0xb0, 0x64, 0x5c, 0xa7, 0xe1, 0x6d, 0xc3, 0x2b, 0x8c,
|
||||
0x61, 0xf7, 0x35, 0x2a, 0xfc, 0xde, 0xd6, 0x4c, 0x33, 0x62, 0x8c, 0x2f, 0x24, 0x2b, 0x75, 0x39,
|
||||
0xed, 0x2b, 0xb8, 0xad, 0x5f, 0xd2, 0x20, 0x3f, 0x55, 0xb7, 0x73, 0x8e, 0x06, 0x82, 0x94, 0xc2,
|
||||
0xb3, 0xe7, 0xa1, 0xbf, 0xd5, 0x29, 0x44, 0xf4, 0x87, 0x2e, 0x0d, 0x4d, 0xeb, 0xe4, 0xea, 0xe7,
|
||||
0x06, 0xa7, 0x50, 0x27, 0x78, 0xc2, 0xc3, 0x3a, 0xc1, 0x5e, 0x61, 0x02, 0xd6, 0x53, 0x7f, 0xe1,
|
||||
0xd7, 0xf6, 0x14, 0x4c, 0xc1, 0xa7, 0x3e, 0xac, 0xe0, 0x75, 0xa0, 0xa6, 0xd4, 0x11, 0x50, 0xaf,
|
||||
0x47, 0x40, 0x23, 0x2a, 0xcf, 0xfc, 0x26, 0x21, 0x37, 0x28, 0xb5, 0x59, 0x37, 0xb3, 0x23, 0xc8,
|
||||
0x7d, 0x42, 0xa0, 0x0f, 0xb2, 0xc3, 0x64, 0x17, 0xf4, 0x9c, 0x2c, 0xa4, 0xb6, 0x56, 0x2d, 0xe2,
|
||||
0x11, 0x3d, 0x27, 0xb0, 0x03, 0x1e, 0x4c, 0x1e, 0x77, 0x42, 0x62, 0x14, 0xc9, 0xb3, 0x1b, 0x54,
|
||||
0xd5, 0x6c, 0x24, 0x70, 0x02, 0xb8, 0x61, 0x70, 0xe1, 0x0b, 0x90, 0x13, 0x09, 0x93, 0x7e, 0x07,
|
||||
0xf1, 0x36, 0x91, 0xea, 0x65, 0x4e, 0x6b, 0xa6, 0xc2, 0xa0, 0x5f, 0xca, 0x1e, 0x25, 0x4c, 0x7e,
|
||||
0xab, 0x15, 0x07, 0x75, 0x2f, 0x2b, 0xc6, 0xab, 0x10, 0xbe, 0x06, 0x0f, 0x27, 0xdd, 0x1c, 0x9b,
|
||||
0x67, 0xb4, 0xf9, 0xe3, 0x41, 0xbf, 0xf4, 0xe0, 0x70, 0xbc, 0x61, 0x84, 0x32, 0x19, 0xdc, 0x08,
|
||||
0xac, 0x07, 0xdc, 0x36, 0x21, 0x09, 0xe1, 0x3e, 0x27, 0x3f, 0x22, 0x1e, 0xfa, 0x09, 0xe1, 0x98,
|
||||
0xc4, 0x12, 0xb5, 0x88, 0x0b, 0x16, 0x10, 0xf8, 0x23, 0x83, 0xee, 0x69, 0xf0, 0xc6, 0x08, 0x5b,
|
||||
0x0d, 0x08, 0x9f, 0xe0, 0x13, 0x82, 0xdb, 0xfe, 0xf8, 0x11, 0xa3, 0xe7, 0x26, 0x22, 0x1a, 0x87,
|
||||
0xe4, 0xd4, 0xc7, 0xac, 0x1b, 0x4b, 0x77, 0x75, 0x01, 0x97, 0x5c, 0xd6, 0x44, 0x7b, 0xd3, 0x3c,
|
||||
0x07, 0x8a, 0x66, 0x4f, 0xb1, 0x5c, 0xdf, 0x6e, 0xb2, 0xff, 0x47, 0xbb, 0xd9, 0xfa, 0x79, 0x19,
|
||||
0x3c, 0x9e, 0x33, 0xc3, 0xe8, 0x5e, 0x3b, 0x1e, 0x14, 0x74, 0x3b, 0x30, 0x3d, 0x22, 0x37, 0x16,
|
||||
0x1f, 0xab, 0xc6, 0x10, 0x80, 0xcd, 0xf9, 0xd3, 0x95, 0x7d, 0xf7, 0x37, 0x2b, 0x66, 0x14, 0xae,
|
||||
0x0c, 0x47, 0xe1, 0xca, 0xf1, 0x70, 0x14, 0xae, 0xa5, 0x55, 0x50, 0x6f, 0x2e, 0x4a, 0x8e, 0xe7,
|
||||
0xce, 0x9b, 0x9a, 0x20, 0x01, 0x79, 0x1a, 0x4b, 0xc2, 0x89, 0x90, 0x37, 0x6f, 0xc0, 0xb3, 0x09,
|
||||
0x91, 0x1b, 0x82, 0xda, 0xf3, 0xf8, 0xcd, 0x01, 0x0f, 0xaf, 0x9d, 0xa9, 0x3e, 0xfc, 0x34, 0x08,
|
||||
0xc8, 0x4f, 0x8d, 0x77, 0xa6, 0x8b, 0xde, 0xf6, 0x25, 0xbc, 0x3a, 0xd2, 0xd5, 0x5e, 0xbe, 0x1b,
|
||||
0x14, 0x9d, 0xf7, 0x83, 0xa2, 0xf3, 0xcf, 0xa0, 0xe8, 0xbc, 0xb9, 0x2c, 0x2e, 0xbd, 0xbf, 0x2c,
|
||||
0x2e, 0xfd, 0x75, 0x59, 0x5c, 0xfa, 0xee, 0xd3, 0x09, 0x7c, 0x35, 0x6c, 0xed, 0x44, 0x28, 0x10,
|
||||
0xfa, 0xab, 0x7a, 0xaa, 0xff, 0xd5, 0xd0, 0x14, 0xc1, 0x8a, 0xbe, 0x89, 0x2f, 0xfe, 0x0b, 0x00,
|
||||
0x00, 0xff, 0xff, 0xe6, 0x31, 0x9b, 0x4e, 0x27, 0x0d, 0x00, 0x00,
|
||||
// 1208 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xdd, 0x6e, 0x1a, 0xc7,
|
||||
0x17, 0xf7, 0xda, 0xc4, 0x81, 0xb1, 0x63, 0xf0, 0xc4, 0x49, 0xd6, 0x8e, 0xfe, 0xc0, 0xdf, 0x55,
|
||||
0x1b, 0x7a, 0x11, 0x50, 0x52, 0x29, 0x52, 0xa5, 0xa8, 0x69, 0xd6, 0x28, 0x11, 0x4a, 0x2a, 0xa1,
|
||||
0xb5, 0xaf, 0xda, 0x8b, 0xd5, 0xec, 0xec, 0x80, 0x47, 0x2c, 0x3b, 0xdb, 0x99, 0x81, 0x26, 0x79,
|
||||
0x85, 0xaa, 0x6a, 0xd4, 0x97, 0xa8, 0x14, 0xf5, 0xb2, 0x0f, 0x91, 0xde, 0x45, 0xbd, 0xaa, 0x7a,
|
||||
0x41, 0x2a, 0xf2, 0x22, 0xd5, 0x7c, 0x00, 0x6b, 0x30, 0x52, 0x64, 0xd3, 0x1b, 0x76, 0xe7, 0x7c,
|
||||
0xfc, 0xce, 0xc7, 0x9c, 0x73, 0xf6, 0x00, 0xca, 0x3d, 0x34, 0x44, 0x0d, 0x1c, 0xa5, 0x8d, 0xe1,
|
||||
0xbd, 0x90, 0x48, 0x74, 0xaf, 0xd1, 0x25, 0x09, 0x11, 0x54, 0xd4, 0x53, 0xce, 0x24, 0x83, 0x25,
|
||||
0xc5, 0xaf, 0xe3, 0x28, 0xad, 0x5b, 0xfe, 0x41, 0x19, 0x33, 0xd1, 0x67, 0xa2, 0x11, 0x22, 0x41,
|
||||
0xa6, 0x4a, 0x98, 0xd1, 0xc4, 0x68, 0x1c, 0xec, 0x1b, 0x7e, 0xa0, 0x4f, 0x0d, 0x73, 0xb0, 0xac,
|
||||
0xbd, 0x2e, 0xeb, 0x32, 0x43, 0x57, 0x6f, 0x96, 0x5a, 0xe9, 0x32, 0xd6, 0x8d, 0x49, 0x43, 0x9f,
|
||||
0xc2, 0x41, 0xa7, 0x21, 0x69, 0x9f, 0x08, 0x89, 0xfa, 0xa9, 0x15, 0x38, 0x58, 0xf0, 0x51, 0xf9,
|
||||
0xa3, 0x79, 0x87, 0x7f, 0xe4, 0xc0, 0xf6, 0x53, 0xe3, 0xf1, 0xb1, 0x44, 0x92, 0xc0, 0x07, 0x60,
|
||||
0x33, 0x45, 0x1c, 0xf5, 0x85, 0xeb, 0x54, 0x9d, 0xda, 0xd6, 0x7d, 0xb7, 0x3e, 0x1f, 0x41, 0xbd,
|
||||
0xad, 0xf9, 0x5e, 0xee, 0xed, 0xa8, 0xb2, 0xe6, 0x5b, 0x69, 0xf8, 0x08, 0xe4, 0x70, 0x94, 0x0a,
|
||||
0x77, 0xbd, 0xba, 0x51, 0xdb, 0xba, 0x7f, 0x63, 0x51, 0xeb, 0xa8, 0xd9, 0xf6, 0xf6, 0x94, 0xca,
|
||||
0x78, 0x54, 0xc9, 0x1d, 0x35, 0xdb, 0xe2, 0xcd, 0x7b, 0xf3, 0xf4, 0xb5, 0x22, 0x7c, 0x0a, 0xf2,
|
||||
0x11, 0x49, 0x99, 0xa0, 0x52, 0xb8, 0x1b, 0x1a, 0x64, 0x7f, 0x11, 0xa4, 0x69, 0x24, 0xbc, 0x92,
|
||||
0x02, 0x7a, 0xf3, 0xbe, 0x92, 0xb7, 0x04, 0xe1, 0x4f, 0x95, 0xe1, 0x97, 0xa0, 0x28, 0x24, 0xe2,
|
||||
0x92, 0x26, 0xdd, 0x00, 0x47, 0x69, 0x40, 0x23, 0x37, 0x57, 0x75, 0x6a, 0x39, 0x6f, 0x77, 0x3c,
|
||||
0xaa, 0x5c, 0x3b, 0xb6, 0xac, 0xa3, 0x28, 0x6d, 0x35, 0xfd, 0x6b, 0x22, 0x73, 0x8c, 0xe0, 0xff,
|
||||
0x00, 0x88, 0x48, 0x28, 0x83, 0x88, 0x24, 0xac, 0xef, 0x5e, 0xa9, 0x3a, 0xb5, 0x82, 0x5f, 0x50,
|
||||
0x94, 0xa6, 0x22, 0xc0, 0xdb, 0xa0, 0xd0, 0x65, 0x43, 0xcb, 0xdd, 0xd4, 0xdc, 0x7c, 0x97, 0x0d,
|
||||
0x0d, 0xf3, 0x47, 0x07, 0xdc, 0x4e, 0x39, 0x19, 0x52, 0x36, 0x10, 0x01, 0xc2, 0x78, 0xd0, 0x1f,
|
||||
0xc4, 0x48, 0x52, 0x96, 0x04, 0xfa, 0x3e, 0xdc, 0xab, 0x3a, 0xa6, 0xcf, 0x17, 0x63, 0xb2, 0xe9,
|
||||
0x7f, 0x9c, 0x51, 0x39, 0xa1, 0x7d, 0xe2, 0x55, 0x6d, 0x8c, 0xee, 0x12, 0x01, 0xe1, 0xef, 0x4f,
|
||||
0xec, 0x2d, 0xb0, 0x20, 0x07, 0x25, 0xc9, 0x24, 0x8a, 0x83, 0x94, 0xd3, 0x04, 0xd3, 0x14, 0xc5,
|
||||
0xc2, 0xcd, 0x6b, 0x0f, 0xee, 0x2c, 0xf5, 0xe0, 0x44, 0x29, 0xb4, 0x27, 0xf2, 0x5e, 0xd9, 0xda,
|
||||
0xbf, 0x79, 0x2e, 0x5b, 0xf8, 0x45, 0x79, 0x96, 0x70, 0xf8, 0xdb, 0x26, 0xd8, 0x34, 0xb5, 0x01,
|
||||
0x4f, 0xc1, 0x2e, 0x66, 0x71, 0x8c, 0x24, 0xe1, 0xca, 0x87, 0x49, 0x41, 0x29, 0xfb, 0xff, 0x3f,
|
||||
0xa7, 0x34, 0xa6, 0xa2, 0x5a, 0xdd, 0x73, 0xad, 0xe5, 0xd2, 0x1c, 0x43, 0xf8, 0x25, 0x3c, 0x47,
|
||||
0x81, 0x5f, 0xdb, 0x2b, 0xd3, 0x36, 0xdc, 0x75, 0x5d, 0xb3, 0xb7, 0xcf, 0x2b, 0x9c, 0x50, 0x1a,
|
||||
0x70, 0x53, 0xb6, 0xfa, 0x56, 0x35, 0x01, 0x3e, 0x03, 0xbb, 0xdd, 0x98, 0x85, 0x28, 0x0e, 0x34,
|
||||
0x50, 0x4c, 0xfb, 0x54, 0xba, 0x1b, 0x1a, 0x68, 0xbf, 0x6e, 0xfb, 0x4f, 0x35, 0x6b, 0xc6, 0x5d,
|
||||
0x9a, 0x58, 0x98, 0xa2, 0xd1, 0x54, 0xe8, 0xcf, 0x95, 0x1e, 0x7c, 0x01, 0xf6, 0xc5, 0x80, 0xa7,
|
||||
0xb1, 0xaa, 0x81, 0x01, 0x36, 0xd7, 0x7f, 0xca, 0x89, 0x38, 0x65, 0xb1, 0x29, 0xc3, 0x82, 0xf7,
|
||||
0x50, 0x69, 0xfe, 0x3d, 0xaa, 0x7c, 0xd6, 0xa5, 0xf2, 0x74, 0x10, 0xd6, 0x31, 0xeb, 0xdb, 0x36,
|
||||
0xb7, 0x8f, 0xbb, 0x22, 0xea, 0x35, 0xe4, 0xcb, 0x94, 0x88, 0x7a, 0x2b, 0x91, 0x7f, 0xfe, 0x7e,
|
||||
0x17, 0x58, 0x2f, 0x5a, 0x89, 0xf4, 0x6f, 0x59, 0xf8, 0xc7, 0x06, 0xfd, 0x64, 0x02, 0x0e, 0x63,
|
||||
0x70, 0x7d, 0xde, 0x72, 0xcc, 0xa4, 0x29, 0xe2, 0x4b, 0xda, 0xdc, 0x3d, 0x6b, 0xf3, 0x39, 0x93,
|
||||
0x90, 0x83, 0x9b, 0x3a, 0x5b, 0x8b, 0x41, 0x6e, 0xae, 0xc0, 0xe0, 0x9e, 0xc2, 0x5e, 0x88, 0xb0,
|
||||
0x03, 0x4a, 0x67, 0x6c, 0xaa, 0xf0, 0xae, 0xae, 0xc0, 0xda, 0x4e, 0xc6, 0x9a, 0x8a, 0xed, 0x0e,
|
||||
0x28, 0x62, 0xca, 0xf1, 0x80, 0xca, 0x20, 0xe4, 0x04, 0xf5, 0x08, 0x77, 0xf3, 0x55, 0xa7, 0x96,
|
||||
0xf7, 0x77, 0x2c, 0xd9, 0x33, 0x54, 0xf8, 0x10, 0x1c, 0xc4, 0xf4, 0xfb, 0x01, 0x8d, 0x4c, 0x9f,
|
||||
0x87, 0x31, 0xc3, 0xbd, 0x80, 0x26, 0x92, 0xf0, 0x21, 0x8a, 0xdd, 0x42, 0xd5, 0xa9, 0x6d, 0xf8,
|
||||
0x6e, 0x46, 0xc2, 0x53, 0x02, 0x2d, 0xcb, 0x3f, 0xfc, 0x65, 0x1d, 0x14, 0xa6, 0x65, 0x09, 0xf7,
|
||||
0xc0, 0x15, 0x33, 0x57, 0x1c, 0x3d, 0x57, 0xcc, 0x41, 0xb9, 0xc2, 0x49, 0x87, 0x70, 0x92, 0x60,
|
||||
0x12, 0x20, 0x21, 0x88, 0xd4, 0x25, 0x5e, 0xf0, 0x77, 0xa6, 0xe4, 0xc7, 0x8a, 0x0a, 0xa9, 0x6a,
|
||||
0xb8, 0x64, 0x48, 0xb8, 0x50, 0x9e, 0x74, 0x10, 0x96, 0x8c, 0xeb, 0x22, 0xbe, 0x6c, 0x72, 0x4a,
|
||||
0x33, 0xd8, 0x27, 0x1a, 0x15, 0x7e, 0x67, 0x3b, 0xae, 0x13, 0x33, 0xc6, 0x57, 0x52, 0xd3, 0xba,
|
||||
0x19, 0x9f, 0x28, 0xb8, 0xc3, 0x9f, 0xf3, 0xa0, 0x38, 0xd7, 0xf5, 0x4b, 0x52, 0x03, 0x41, 0x4e,
|
||||
0xe1, 0xd9, 0x7c, 0xe8, 0x77, 0x95, 0x85, 0xec, 0x85, 0x70, 0xf5, 0xb8, 0x40, 0x16, 0x9a, 0x04,
|
||||
0x67, 0x3c, 0x6c, 0x12, 0xec, 0x97, 0x32, 0xb0, 0xbe, 0xfa, 0x85, 0x5f, 0xd9, 0x2c, 0x98, 0x71,
|
||||
0x91, 0xfb, 0xb8, 0x71, 0xa1, 0x03, 0x35, 0x83, 0x02, 0x01, 0xf5, 0xed, 0x09, 0x69, 0x4c, 0xe5,
|
||||
0xcb, 0xa0, 0x43, 0xc8, 0x05, 0x1a, 0x75, 0xd1, 0xcd, 0xed, 0x29, 0xe4, 0x13, 0x42, 0x60, 0x00,
|
||||
0xb6, 0x27, 0xad, 0x22, 0xe8, 0x2b, 0xb2, 0x92, 0xce, 0xdc, 0xb2, 0x88, 0xc7, 0xf4, 0x15, 0x81,
|
||||
0x7d, 0x70, 0x3d, 0x9b, 0xee, 0x94, 0x24, 0x28, 0x96, 0x2f, 0x2f, 0xd0, 0x93, 0x8b, 0x91, 0xc0,
|
||||
0x0c, 0x70, 0xdb, 0xe0, 0xc2, 0x07, 0x60, 0x47, 0xa4, 0x4c, 0x06, 0x7d, 0xc4, 0x7b, 0x44, 0xaa,
|
||||
0xef, 0x7a, 0x5e, 0x5b, 0x2a, 0x8d, 0x47, 0x95, 0xed, 0xe3, 0x94, 0xc9, 0x6f, 0x34, 0xa3, 0xd5,
|
||||
0xf4, 0xb7, 0xc5, 0xec, 0x14, 0xc1, 0x67, 0xe0, 0x46, 0xd6, 0xcd, 0x99, 0x7a, 0x41, 0xab, 0xdf,
|
||||
0x1a, 0x8f, 0x2a, 0xd7, 0x9f, 0xcf, 0x04, 0xa6, 0x28, 0xd9, 0xe0, 0xa6, 0x60, 0x43, 0xe0, 0xf6,
|
||||
0x08, 0x49, 0x09, 0x0f, 0x38, 0xf9, 0x01, 0xf1, 0x28, 0x48, 0x09, 0xc7, 0x24, 0x91, 0xa8, 0x4b,
|
||||
0x5c, 0xb0, 0x82, 0xc0, 0x6f, 0x1a, 0x74, 0x5f, 0x83, 0xb7, 0xa7, 0xd8, 0x6a, 0xbd, 0xf8, 0x04,
|
||||
0x9f, 0x12, 0xdc, 0x0b, 0x66, 0x9f, 0x40, 0xfa, 0xca, 0x44, 0x44, 0x93, 0x88, 0xbc, 0x08, 0x30,
|
||||
0x1b, 0x24, 0xd2, 0xdd, 0x5a, 0xc1, 0x25, 0x57, 0xb5, 0xa1, 0xa3, 0x79, 0x3b, 0x2d, 0x65, 0xe6,
|
||||
0x48, 0x59, 0x39, 0x7f, 0xdc, 0x6c, 0xff, 0x17, 0xe3, 0xe6, 0xf0, 0xa7, 0x75, 0x70, 0x6b, 0xc9,
|
||||
0x06, 0xa4, 0x27, 0xf5, 0x6c, 0xcd, 0xd0, 0xe3, 0xc0, 0xcc, 0x88, 0x9d, 0x19, 0xf9, 0x44, 0x0d,
|
||||
0x86, 0x10, 0x1c, 0x2c, 0xdf, 0xcd, 0xec, 0xd6, 0x70, 0x50, 0x37, 0x8b, 0x74, 0x7d, 0xb2, 0x48,
|
||||
0xd7, 0x4f, 0x26, 0x8b, 0xb4, 0x97, 0x57, 0x41, 0xbd, 0x7e, 0x5f, 0x71, 0x7c, 0x77, 0xd9, 0xce,
|
||||
0x05, 0x09, 0x28, 0xea, 0xd9, 0x4f, 0x84, 0xbc, 0xf8, 0x00, 0x5e, 0x2c, 0x88, 0x9d, 0x09, 0xa8,
|
||||
0xcd, 0xc7, 0xaf, 0x0e, 0xb8, 0x71, 0xee, 0x46, 0xf6, 0xf1, 0xd9, 0x20, 0xa0, 0x38, 0xb7, 0x1c,
|
||||
0x9a, 0x29, 0x7a, 0xd9, 0xef, 0xe8, 0xd9, 0x85, 0xd0, 0x7b, 0xf4, 0x76, 0x5c, 0x76, 0xde, 0x8d,
|
||||
0xcb, 0xce, 0x3f, 0xe3, 0xb2, 0xf3, 0xfa, 0x43, 0x79, 0xed, 0xdd, 0x87, 0xf2, 0xda, 0x5f, 0x1f,
|
||||
0xca, 0x6b, 0xdf, 0x7e, 0x9a, 0xc1, 0x57, 0xab, 0xda, 0xdd, 0x18, 0x85, 0x42, 0xbf, 0x35, 0x5e,
|
||||
0xe8, 0x3f, 0x2a, 0xda, 0x44, 0xb8, 0xa9, 0x6f, 0xe2, 0x8b, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff,
|
||||
0x5c, 0xdf, 0x27, 0x18, 0x65, 0x0d, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
|
||||
@ -661,6 +671,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.LiquidationBlockInterval != 0 {
|
||||
i = encodeVarintGenesis(dAtA, i, uint64(m.LiquidationBlockInterval))
|
||||
i--
|
||||
dAtA[i] = 0x48
|
||||
}
|
||||
if m.CircuitBreaker {
|
||||
i--
|
||||
if m.CircuitBreaker {
|
||||
@ -1108,6 +1123,9 @@ func (m *Params) Size() (n int) {
|
||||
if m.CircuitBreaker {
|
||||
n += 2
|
||||
}
|
||||
if m.LiquidationBlockInterval != 0 {
|
||||
n += 1 + sovGenesis(uint64(m.LiquidationBlockInterval))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -1798,6 +1816,25 @@ func (m *Params) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
m.CircuitBreaker = bool(v != 0)
|
||||
case 9:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LiquidationBlockInterval", wireType)
|
||||
}
|
||||
m.LiquidationBlockInterval = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenesis
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.LiquidationBlockInterval |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenesis(dAtA[iNdEx:])
|
||||
|
@ -21,6 +21,7 @@ var (
|
||||
KeyDebtLot = []byte("DebtLot")
|
||||
KeySurplusThreshold = []byte("SurplusThreshold")
|
||||
KeySurplusLot = []byte("SurplusLot")
|
||||
KeyBeginBlockerExecutionBlockInterval = []byte("BeginBlockerExecutionBlockInterval")
|
||||
DefaultGlobalDebt = sdk.NewCoin(DefaultStableDenom, sdk.ZeroInt())
|
||||
DefaultCircuitBreaker = false
|
||||
DefaultCollateralParams = CollateralParams{}
|
||||
@ -39,12 +40,14 @@ var (
|
||||
DefaultSurplusLot = sdkmath.NewInt(10000000000)
|
||||
DefaultDebtLot = sdkmath.NewInt(10000000000)
|
||||
stabilityFeeMax = sdk.MustNewDecFromStr("1.000000051034942716") // 500% APR
|
||||
// Run every block
|
||||
DefaultBeginBlockerExecutionBlockInterval = int64(1)
|
||||
)
|
||||
|
||||
// NewParams returns a new params object
|
||||
func NewParams(
|
||||
debtLimit sdk.Coin, collateralParams CollateralParams, debtParam DebtParam, surplusThreshold,
|
||||
surplusLot, debtThreshold, debtLot sdkmath.Int, breaker bool,
|
||||
surplusLot, debtThreshold, debtLot sdkmath.Int, breaker bool, beginBlockerExecutionBlockInterval int64,
|
||||
) Params {
|
||||
return Params{
|
||||
GlobalDebtLimit: debtLimit,
|
||||
@ -55,6 +58,7 @@ func NewParams(
|
||||
DebtAuctionThreshold: debtThreshold,
|
||||
DebtAuctionLot: debtLot,
|
||||
CircuitBreaker: breaker,
|
||||
LiquidationBlockInterval: beginBlockerExecutionBlockInterval,
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +67,7 @@ func DefaultParams() Params {
|
||||
return NewParams(
|
||||
DefaultGlobalDebt, DefaultCollateralParams, DefaultDebtParam, DefaultSurplusThreshold,
|
||||
DefaultSurplusLot, DefaultDebtThreshold, DefaultDebtLot,
|
||||
DefaultCircuitBreaker,
|
||||
DefaultCircuitBreaker, DefaultBeginBlockerExecutionBlockInterval,
|
||||
)
|
||||
}
|
||||
|
||||
@ -122,6 +126,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
|
||||
paramtypes.NewParamSetPair(KeySurplusLot, &p.SurplusAuctionLot, validateSurplusAuctionLotParam),
|
||||
paramtypes.NewParamSetPair(KeyDebtThreshold, &p.DebtAuctionThreshold, validateDebtAuctionThresholdParam),
|
||||
paramtypes.NewParamSetPair(KeyDebtLot, &p.DebtAuctionLot, validateDebtAuctionLotParam),
|
||||
paramtypes.NewParamSetPair(KeyBeginBlockerExecutionBlockInterval, &p.LiquidationBlockInterval, validateBeginBlockerExecutionBlockIntervalParam),
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,6 +148,10 @@ func (p Params) Validate() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateBeginBlockerExecutionBlockIntervalParam(p.LiquidationBlockInterval); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateSurplusAuctionThresholdParam(p.SurplusAuctionThreshold); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -346,3 +355,16 @@ func validateDebtAuctionLotParam(i interface{}) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateBeginBlockerExecutionBlockIntervalParam(i interface{}) error {
|
||||
bbebi, ok := i.(int64)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid parameter type: %T", i)
|
||||
}
|
||||
|
||||
if bbebi <= 0 {
|
||||
return fmt.Errorf("begin blocker execution block interval param should be positive: %d", bbebi)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold sdkmath.Int
|
||||
debtLot sdkmath.Int
|
||||
breaker bool
|
||||
beginBlockerExecutionBlockInterval int64
|
||||
}
|
||||
type errArgs struct {
|
||||
expectPass bool
|
||||
@ -50,6 +51,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: true,
|
||||
@ -87,6 +89,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: true,
|
||||
@ -124,6 +127,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -161,6 +165,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -212,6 +217,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: true,
|
||||
@ -263,6 +269,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -314,6 +321,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -350,6 +358,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -387,6 +396,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -438,6 +448,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -489,6 +500,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: true,
|
||||
@ -526,6 +538,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -563,6 +576,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -600,6 +614,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -637,6 +652,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -669,6 +685,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -706,6 +723,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -723,6 +741,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -740,6 +759,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -757,6 +777,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: sdk.ZeroInt(),
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -774,6 +795,7 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
@ -791,16 +813,53 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: sdk.ZeroInt(),
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: types.DefaultBeginBlockerExecutionBlockInterval,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "debt auction lot should be positive",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "zero begin blocker execution interval",
|
||||
args: args{
|
||||
globalDebtLimit: types.DefaultGlobalDebt,
|
||||
collateralParams: types.DefaultCollateralParams,
|
||||
debtParam: types.DefaultDebtParam,
|
||||
surplusThreshold: types.DefaultSurplusThreshold,
|
||||
surplusLot: types.DefaultSurplusLot,
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: 0,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "begin blocker execution block interval param should be positive",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negative begin blocker execution interval",
|
||||
args: args{
|
||||
globalDebtLimit: types.DefaultGlobalDebt,
|
||||
collateralParams: types.DefaultCollateralParams,
|
||||
debtParam: types.DefaultDebtParam,
|
||||
surplusThreshold: types.DefaultSurplusThreshold,
|
||||
surplusLot: types.DefaultSurplusLot,
|
||||
debtThreshold: types.DefaultDebtThreshold,
|
||||
debtLot: types.DefaultDebtLot,
|
||||
breaker: types.DefaultCircuitBreaker,
|
||||
beginBlockerExecutionBlockInterval: -1,
|
||||
},
|
||||
errArgs: errArgs{
|
||||
expectPass: false,
|
||||
contains: "begin blocker execution block interval param should be positive",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
params := types.NewParams(tc.args.globalDebtLimit, tc.args.collateralParams, tc.args.debtParam, tc.args.surplusThreshold, tc.args.surplusLot, tc.args.debtThreshold, tc.args.debtLot, tc.args.breaker)
|
||||
params := types.NewParams(tc.args.globalDebtLimit, tc.args.collateralParams, tc.args.debtParam, tc.args.surplusThreshold, tc.args.surplusLot, tc.args.debtThreshold, tc.args.debtLot, tc.args.breaker, tc.args.beginBlockerExecutionBlockInterval)
|
||||
err := params.Validate()
|
||||
if tc.errArgs.expectPass {
|
||||
suite.Require().NoError(err)
|
||||
|
@ -18,6 +18,7 @@ func NewCDPGenState(cdc codec.JSONCodec, denom, asset string, liquidationRatio s
|
||||
SurplusAuctionLot: cdptypes.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: cdptypes.DefaultDebtThreshold,
|
||||
DebtAuctionLot: cdptypes.DefaultDebtLot,
|
||||
LiquidationBlockInterval: cdptypes.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: cdptypes.CollateralParams{
|
||||
{
|
||||
Denom: denom,
|
||||
|
@ -28,6 +28,7 @@ func NewCDPGenStateMulti(cdc codec.JSONCodec) app.GenesisState {
|
||||
SurplusAuctionLot: cdptypes.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: cdptypes.DefaultDebtThreshold,
|
||||
DebtAuctionLot: cdptypes.DefaultDebtLot,
|
||||
LiquidationBlockInterval: cdptypes.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: cdptypes.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
|
@ -34,6 +34,7 @@ func NewCDPGenStateMulti(cdc codec.JSONCodec) app.GenesisState {
|
||||
SurplusAuctionLot: cdptypes.DefaultSurplusLot,
|
||||
DebtAuctionThreshold: cdptypes.DefaultDebtThreshold,
|
||||
DebtAuctionLot: cdptypes.DefaultDebtLot,
|
||||
LiquidationBlockInterval: cdptypes.DefaultBeginBlockerExecutionBlockInterval,
|
||||
CollateralParams: cdptypes.CollateralParams{
|
||||
{
|
||||
Denom: "xrp",
|
||||
|
Loading…
Reference in New Issue
Block a user